Some questions about the createItem function

116 views
Skip to first unread message

AM

unread,
Mar 11, 2018, 7:10:49 AM3/11/18
to mirt-package
Dear Phil,

I am trying to understand how exactly does the syntax for the createItem function work. If you would have the time to help me out, could you show me the code on how would one use the createItem function to create the item type of graded response model, if it wasn't already included in the mirt package in the same manner as the nominal response model is shown in the CRAN documentation? Also, I am wondering which values should be used for the starting values of parameters and how this choice could impact the results of the calculations.

Thanks!

Phil Chalmers

unread,
Mar 11, 2018, 12:11:15 PM3/11/18
to AM, mirt-package
Try writing out a probability traceline function reflecting this model. After that, translating it into something for createItem is a breeze. 

Phil

--
You received this message because you are subscribed to the Google Groups "mirt-package" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mirt-package+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Message has been deleted

Phil Chalmers

unread,
Mar 12, 2018, 10:51:14 AM3/12/18
to AM, mirt-package
I wouldn't set the problem up this way. First, build a matrix with all the 2PL traceline functions, then write a for loop computing the differences between these response functions from the highest column to lowest (the lowest column should be just a column of ones). 


Phil

On Mon, Mar 12, 2018 at 10:46 AM, AM <mut...@gmail.com> wrote:
Dear Phil,

I was trying to write out the probability traceline function for GRM. However, after passing it to the createItem function and running the mirt function, I get the following errors:

In log(itemtrace) : NaNs produced
M-step optimizer converged immediately. Solution is either at the ML or starting values are causing issues and should be adjusted. 

Could you please help me and point out what I'm doing wrong? Here's my code (I'm trying to recreate the graded response model):

par<-c(a=.5,b=rep(1.3,4))
est<-rep(TRUE,length(par))

p.grm<-function(par,Theta,ncat){
    a<-par[1]
    b<-par[2:length(par)]
    z<-matrix(0,nrow(Theta),ncat)
    for (i in 1:ncat){
        if (i==1){
            z[,i]<-1-(exp(a*(Theta-b[i])))/(1+exp(a*(Theta-b[i])))
        } else if (i == ncat){
            z[,i]<-(exp(a*(Theta-b[i])))/(1+exp(a*(Theta-b[i])))
        } else {
            z[,i]<-(exp(a*(Theta-b[i])))/(1+exp(a*(Theta-b[i])))-(exp(a*(Theta-b[i+1])))/(1+exp(a*(Theta-b[i+1])))
        }
     
        
    }
z    
}

GRMtest<-createItem(name = "GRMtest", par=par, est=est,P=p.grm)
fit.ac.grmtest<-mirt(ac, 1, 'GRMtest', customItems=list(GRMtest=GRMtest))

Phil

To unsubscribe from this group and stop receiving emails from it, send an email to mirt-package...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

AM

unread,
Mar 12, 2018, 12:46:33 PM3/12/18
to mirt-p...@googlegroups.com
Dear Phil,

I tried to revise my code and now it looks like this:

par<-c(a=.5,b=rep(1.3,4))
est<-rep(TRUE,length(par))

p.grm<-function(par,Theta,ncat){
    a<-par[1]
    b<-par[2:length(par)]
    z<-matrix(0,nrow(Theta),ncat)
    y<-matrix(0,nrow(Theta),ncat)
    y[,1]<-1
    for(i in 1:ncat-1){
        y[,i+1]<-(exp(a*(Theta-b[i])))/(1+exp(a*(Theta-b[i])))
    }
    for(i in 1:ncat-1){
        z[,i]<-y[,i]-y[,i+1]
    }
    z[,ncat]<-y[,ncat]
    z
}

GRMtest<-createItem(name = "GRMtest", par=par, est=est,P=p.grm)
fit.ac.grmtest<-mirt(ac, 1, 'GRMtest', customItems=list(GRMtest=GRMtest))

However, when I run it, I get the error "Error: dims [product 61] do not match the length of object [0]
Called from: x@P(x@par, Theta = Theta, ncat = x@ncat)" and this error is estimated to be in the line "y[,i+1]<-(exp(a*(Theta-b[i])))/(1+exp(a*(Theta-b[i])))"

Any help would be greatly appreciated! Thank you. 
(Sorry, I'm not familiar with C++)

AM

unread,
Mar 14, 2018, 10:37:57 AM3/14/18
to mirt-package
Dear Phil,

The error which I described above was not related to the mirt package. I revised my code and now it looks like this:

par<-c(a=.5,b=rep(1.3,4))
est<-rep(TRUE,length(par))

p.grm<-function(par,Theta,ncat){
  a<-par[1]
  b<-par[2:length(par)]
  z<-matrix(0,nrow(Theta),ncat)
  y<-matrix(0,nrow(Theta),ncat)
  y[,1]<-1
  for(i in 1:(ncat-1)){
    y[,i+1]<-(exp(a*(Theta-b[i])))/(1+exp(a*(Theta-b[i])))
  }
  for(i in 1:(ncat-1)){
    z[,i]<-y[,i]-y[,i+1]
  }
  z[,ncat]<-y[,ncat]
  return(z)
}

GRMtest<-createItem(name = "GRMtest", par=par, est=est,P=p.grm)
fit.ac.grmtest<-mirt(ac, 1, 'GRMtest', customItems=list(GRMtest=GRMtest))

However, I'm still getting the errors that I was getting the first time: "In log(itemtrace) : NaNs produced" and
"M-step optimizer converged immediately. Solution is either at the ML or starting values are causing issues and should be adjusted."

Please, could you help to solve this error? Do you perhaps have some ideas about starting values for parameters that I should use? Perhaps 0.5 and 1.3 are not good values? I would be really grateful if you could help me as I require knowledge of the createItem function to do some calculations for my thesis. 

Phil Chalmers

unread,
Mar 14, 2018, 11:57:16 AM3/14/18
to AM, mirt-package
Your probability traceline does not look correct. Try testing it in isolation before passing it to createItem to ensure that it works correctly first. E.g., I can see that you have a for(i in 1:ncat-1){...} block, which doesn't work because R does not use index of 0 locations to fill matricies. 

Phil

To unsubscribe from this group and stop receiving emails from it, send an email to mirt-package+unsubscribe@googlegroups.com.

AM

unread,
Apr 24, 2018, 1:25:05 AM4/24/18
to mirt-package
Dear Phil, 

I have been struggling with this for over a month. I'm trying to use the createItem function to create the graded response model. This is my current code:

par<-c(-0.685,1.06,-0.474,-1.612,-3.417)
names(par)<-c("a","b1","b2","b3","b4")
est<-rep(TRUE,length(par))
Theta<-matrix(c(-6,-5.8,-5.6,-5.4,-5.2,-5,-4.8,-4.6,-4.4,-4.2,-4,-3.8,-3.6,-3.4,-3.2,-3,-2.8,-2.6,-2.4,-2.2,-2,-1.8,-1.6,-1.4,-1.2,-1,-0.8,-0.6,-0.4,-0.2,0,0.2,0.4,0.6,0.8,1,1.2,1.4,1.6,1.8,2,2.2,2.4,2.6,2.8,3,3.2,3.4,3.6,3.8,4,4.2,4.4,4.6,4.8,5,5.2,5.4,5.6,5.8,6))

p.grm.old<-function(par,Theta,ncat){
  a<-par[1]
  b<-par[2:5]
  intermediate<-matrix(1, nrow = nrow(Theta), ncol = ncat+1)
  intermediate[,ncat+1]<-0
  final<-matrix(0, nrow = nrow(Theta), ncol = ncat)
  for (i in 2:ncat){
    intermediate[,i]<-((exp(a*(Theta-b[[i-1]])))/(1+exp(a*(Theta-b[[i-1]]))))
  }
  for (j in ncat:1){
   final[,j]<-intermediate[,j]-intermediate[,j+1]
  }
  final
}


GRMold<-createItem(name = "GRMold", par=par, est=est,P=p.grm.old)
fit.l.grmtest<-mirt(L, 1, 'GRMold', customItems=list(GRMold=GRMold), technical = list(removeEmptyRows = T))

When I test it in isolation, it seems to work fine. However, when I run it through mirt, I get different coefficients and different tracelines than those that I would obtain if I calculated the graded response model that's already included in your package. (itemtype = "graded"). 
Please, could you give me some hints on what I could be doing wrong? As you suggested earlier, first I built a matrix containing all the 2PL probability tracelines. The first column contains all ones. After that, I have a for loop calculating differences between those probabilites. However, the last category function is identical to the last 2PL traceline probability; in order to have something to substract it from in the for loop, I added an extra column to the 2PL probabilites matrix which contains all zeroes (otherwise I get the subscript out of bounds error). Is this what's causing estimation problems? Could you please describe how did you handle it on the C++ level? Unfortunately, I'm unfamiliar with C++ and I can't follow the link that you have sent.

Phil Chalmers

unread,
Apr 27, 2018, 4:14:12 PM4/27/18
to Augustin Mutak, mirt-package
Your model looks fine to me, here's the comparison to mirt. The errors you are seeing could be due to poor starting values (you start at a negative discrimination for some reason), plus this classical IRT form is prone to being very unstable...which is why mirt doesn't support it by default. 

#-----------------------------------------------------
library(mirt)

mod <- mirt(Science, 1)
IRTpar1 <- coef(mod, IRTpars=TRUE)[[1]]
p1 <- extract.item(mod, 1)

par<-as.numeric(IRTpar1)
names(par)<-c("a","b1","b2","b3")
est<-rep(TRUE,length(par))
Theta<-matrix(seq(-6, 6, by=.2))

p.grm.old<-function(par,Theta,ncat){
a<-par[1]
b<-par[-1]
intermediate<-matrix(1, nrow = nrow(Theta), ncol = ncat+1)
intermediate[,ncat+1]<-0
final<-matrix(0, nrow = nrow(Theta), ncol = ncat)
for (i in 2:ncat){
intermediate[,i]<-((exp(a*(Theta-b[[i-1]])))/(1+exp(a*(Theta-b[[i-1]]))))
}
for (j in ncat:1){
final[,j]<-intermediate[,j]-intermediate[,j+1]
}
final
}

# compare
p.grm.old(par, Theta, 4)
probtrace(p1, Theta)

GRMold<-createItem(name = "GRMold", par=par, est=est,P=p.grm.old)
fit.l.grmtest<-mirt(Science, 1, 'GRMold', customItems=list(GRMold=GRMold))

# roughly the same log-likelihood
anova(mod, fit.l.grmtest)

Phil

AM

unread,
Apr 28, 2018, 1:50:51 AM4/28/18
to mirt-package
Hi Phil!

Thank you so much, this has been really helpful! I've tried to follow what you did and I set the starting parameter values to those obtained through regular GRM. Also, I tried to change the parametrization to slope-intercept form to improve the stability of the model. After that, the script seems to work totally fine!

Just wanted to share with you what I'm trying to do: I'm trying to extend the 3PL model to polytomous data and calculate a 3PL GRM model. If you're interested, this is my code so far. It doesn't seem stable, but I'll have to work on trying to improve it during the next weeks:

fit.l.grm<-mirt(L, 1)
IRTpar1 <- coef(fit.l.grm)[[1]]
p1 <- extract.item(fit.l.grm, 1)

par<-as.numeric(c(IRTpar1,.3))
names(par)<-c("a","d1","d2","d3","d4","z")
est<-rep(TRUE,length(par))
Theta<-matrix(seq(-6, 6, by=.2))

p.grm.3pl<-function(par,Theta,ncat){
  a<-par[1]
  d<-par[c(-1,-length(par))]
  z<-par[length(par)]
  intermediate<-matrix(1, nrow = nrow(Theta), ncol = ncat+1)
  intermediate[,ncat+1]<-0
  final<-matrix(0, nrow = nrow(Theta), ncol = ncat)
  for (i in 2:ncat){
    intermediate[,i]<-(exp(z)/(1+exp(z)))+(1/(1+exp(z))*exp((a*Theta)+d[i-1])/(1+exp((a*Theta)+d[i-1])))
  }
  for (j in ncat:1){
    final[,j]<-intermediate[,j]-intermediate[,j+1]
  }
  final
}

p.grm.3pl(par, Theta, 4)
probtrace(p1, Theta)

GRM3PL<-createItem(name = "GRM3PL", par=par, est=est,P=p.grm.3pl)
fit.l.grm3pl<-mirt(L, 1, 'GRM3PL', customItems=list(GRM3PL=GRM3PL))
Reply all
Reply to author
Forward
0 new messages