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
@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]) ;
}