Multilevel model with 2 dimensions parameter

Hi!
I am trying to build a kind of a IRT model using multiple parameters for each person, one for each required skill.

I wanted to model it in a hierarchical way, so that every person parameter has a prior and latter these people share a common prior as well.

My question is:
How to do that in an efficient way, since my parameter has 2 dimensions? My attempt was this:

matrix[J, K] theta;
    for (i in 1:J){
        theta[i] = to_row_vector(rep_array(theta_g[i], K));
    }   

is it correct? Does it makes sense?

Full code:

   data{
    int<lower=1> J;  // # of students
    int<lower=1> K;  // # of skills
    int<lower=1> I;  // # of questions
    int<lower=1> N; // total # of answers
    int Q[I, K];  // Q matrix
    int<lower=0, upper=1> y[N];   // correctness for n
    int ii[N];   // question index
    int jj[N];   // person for n
}

parameters {
    vector[I] beta;
    vector[J] theta_g;
}
transformed parameters{
    matrix[J, K] theta;
    for (i in 1:J){
        theta[i] = to_row_vector(rep_array(theta_g[i], K));
    }   
}
model {
    theta_g ~ normal(0, 10);
    beta ~ normal(0, 1);
    for (n in 1:N){
        real alpha;
        // skills required by the question
        alpha = dot_product(to_row_vector(Q[ii[n]]), theta[jj[n]]);
        y[n] ~ bernoulli_logit(alpha - beta[ii[n]]);
    }
}

Thanks

I don’t think your code implements any kind of reasonable model. If you want each of J students to be associated with K latent skill values, then you need a parameter variable with J\times K values. The way you have it now, each student gets the identical value for all their skills. I think what you want is:

...
parameters {
    vector[I] beta;
    matrix[J, K] theta;
}
model {
    to_vector(theta) ~ normal(0, 10) ;
    beta ~ normal(0, 1);
    for (n in 1:N){
        real alpha;
        // skills required by the question
        alpha = dot_product(to_row_vector(Q[ii[n]]), theta[jj[n]]);
        y[n] ~ bernoulli_logit(alpha - beta[ii[n]]);
    }
}

Now, that’s an “unpooled” model, where the different students don’t mutually inform at all. I suspect you will want a “partially-pooled” model instead. Here’s one that has partial-pooling for both student and skill

...
parameters {
    vector[I] beta;
    matrix[J, K] theta;
    vector[J] mu_j ;
    vector<lower=0>[J] sigma_j ;
    vector[K] mu_k ;
    vector<lower=0>[K] sigma_k ;
}
model {
    mu_j ~ normal(0,1) ;
    mu_k ~ normal(0,1) ;
    sigma_k ~ weibull(2,1) ; #peaked around .8, zero at zero, 2%>2
    sigma_j ~ weibull(2,1) ; #peaked around .8, zero at zero, 2%>2
    for(j in 1:J){
        theta[j,] ~ normal(mu_j, sigma_j) ;
    }
    for(k in 1:K){
        theta[,k] ~ normal(mu_k, sigma_k) ;
    }
    beta ~ normal(0, 1);
    for (n in 1:N){
        real alpha;
        // skills required by the question
        alpha = dot_product(to_row_vector(Q[ii[n]]), theta[jj[n]]);
        y[n] ~ bernoulli_logit(alpha - beta[ii[n]]);
    }
}
1 Like

perfect, makes sense!!!

thanks!!!

@mike-lawrence
just one detail, it should be like this, right ?

for(j in 1:J){
        theta[j,] ~ normal(mu_j[j], sigma_j[j]);
 }
 for(k in 1:K){
        theta[,k] ~ normal(mu_k[k], sigma_k[k]) ;
 }

Ah, yes, good catch