Up

Item Response Theory of Stage Theory

A simple sample script in Stan

Yasuharu Okamoto

 

Item response theory (IRT) usually assumes that the ability is continuous variable, but in psychology, it is not rare to assume that ability is represented by stages. A famous stage theory is one by Piaget. Okamoto (2013) presented a model of stage theory by extension of item response theory. In this website, we present a simple script in Stan of stage theory based on Okamoto (2013)fs model. For general introduction, see Levy and Mislevy (2016).

We assume three stages, stage-0, stage-1, and stage-2, for simplicity. Stages cannot be observed, so may be called latent classes. Probability of correct answer on an item is dependent on the stage in which the person is, and increases from stage-0, stage-1 to stage-2. In Okamoto (2013), this increase in probability of correct response is represented using inverse logit function (cumulative logistic function). Also in the following script, increasing probabilities are represented by inverse logistic function, inv_logit function, with stacking simplex variables rescaled. Running this script, we get estimations of the probabilities of a person in stages, , and the probabilities of correct response of a person in a stage, . Stan cannot use categorical parameters and stages are categorical variables. Hence, the script in the following uses marginalization to treat categorical parameters, that is,

 

A sample script for stage theory is given as follows:

 

 

"""

      Yasuharu Okamoto, 2018.11, 2019.02

 

"""

import pystan

import pickle

import matplotlib.pyplot as plt

import seaborn as sb

import numpy as np

 

X = ([[1]*5 + [1]*5] * 7) + ([[2]*5 + [1]*5] * 7) + \

     ([[2]*5 + [2]*5] * 7)

 

print('X =')

for v in X:

    print(v)

N = len(X)

print('N = ', N)

M = len(X[0])

print('M = ', M)

NStg = 3

print('NStg = ', NStg)

 

stan_data = {'N': N, 'M': M, 'NStg': NStg, 'X': X}

 

stan_code = """

 

//

//      Binary Responses for Three Latent Classes

//                                  Y. Okamoto

//

data {

    int N;          //  Number of subjects

    int M;          //  Number of items

    int NStg;       //  Number of stages

    int X[N, M];    //  Responses:  1 -> failure, 2 -> success

}

parameters {

    simplex[NStg+1] Cintvl[M];    //  Intervals of criterions

    simplex[NStg] theta[N];

}

transformed parameters {

    vector[NStg] C[M];

    real p[M, NStg];

    real p_person[N, M];

    vector[2] p_person_cat[N, M];

 

    for (i in 1:M){

        for (stg in 1:NStg) {

            if ( stg == 1 ) {

                C[i][1] = -5 + Cintvl[i][1] * 10.0;

            }

            else {

                C[i][stg] = C[i][stg - 1] + Cintvl[i][stg] * 10.0;

            };

        }

    }

    for (i in 1:M) {

        for (stg in 1:NStg) {

                p[i][stg] = inv_logit(C[i][stg]);

            }

    }

   

    for (j in 1:N) {

        for (i in 1:M){

            p_person[j][i] = 0.0;

            for (stg in 1:NStg){

                p_person[j][i] = p_person[j][i] + p[i][stg] * theta[j][stg];

            }

        }

    }

    for (j in 1:N) {

        for (i in 1:M) {

            p_person_cat[j][i][2] = p_person[j][i];

            p_person_cat[j][i][1] = 1.0 - p_person_cat[j][i][2];

        }

    }

}

model {

    for (j in 1:N) {

        for (i in 1:M){

            X[j][i] ~ categorical(p_person_cat[j][i]);

        }

    }

}

 

"""

 

sm = pystan.StanModel(model_code = stan_code)

with open('model.pkl', 'wb') as g:

    pickle.dump(sm, g)

 

fit = sm.sampling(data = stan_data, n_jobs = 1)

 

p_samples = fit['p']

 

p_item_stage = np.empty((M, NStg))

for i in range(M):

    for s in range(NStg):

        p_item_stage[i][s] = p_samples[:,i,s].mean()

 

print('\n\nP(correct|item,stage)\n')

print('{0:>7s}{1:>9s}{2:>9s}{3:>9s}'.format(' ', 'Stage-0', 'Stage-1', 'Stage-2'))

for i in range(M):

    print('Item-{0} '.format(i), end = '')

    for s in range(NStg):

        print('{0:>9.5f}'.format(p_item_stage[i][s]), end = '')

    print(' ')

 

theta = fit['theta']

p_stage = np.empty((N, NStg))

for j in range(N):

    for s in range(NStg):

        p_stage[j][s] = theta[:,j,s].mean()

 

print('\n\nP(stage|person)\n')

print('{0:>10s}{1:>9s}{2:>9s}{3:>9s}'.format(' ', 'stage-0', 'stage-1', 'stage-2'))

for j in range(N):

    print('Person-{0: <3d}'.format(j), end = '')

    for s in range(NStg):

        print('{0:>9.5f}'.format(p_stage[j][s]), end = '')

    print(' ')

 

 

The data is set by this code of the above script:

 

X = ([[1]*5 + [1]*5] * 7) + ([[2]*5 + [1]*5] * 7) + \

     ([[2]*5 + [2]*5] * 7)

 

Run the script, we get the following:

 

X =

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 1, 1, 1, 1, 1]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

 

The above output (X =) shows the data generated by the script. Numeral 1 indicates error response, and 2 correct one.

The data consists of  persons, the first 7 person is supposed to be in stage-0, the next 7 person in stage-1, and the rest in stage-2.

The number of items is 10, the first 5 items is easy, so stage-1 or stage-2 person can answer correctly, but stage-0 person cannot answer correctly on all items. The last 5 items can be answered correctly only by a person in stage-2.

In the Stan script, probabilities  are represented by parameter theta , probabilities  by parameter p , and probabilities  by parameter p_person .

 

Estimation of parameters by Bayesian analysis with the Stan script gives these results:

 

Probabilties of correct responses on items by a person in each stage  are

 

P(correct|item,stage)

 

         Stage-0  Stage-1  Stage-2

Item-0   0.06546  0.89806  0.97390

Item-1   0.06758  0.89594  0.97358

Item-2   0.06639  0.89750  0.97394

Item-3   0.06653  0.89628  0.97293

Item-4   0.06806  0.89767  0.97323

Item-5   0.02634  0.10168  0.93298

Item-6   0.02651  0.10224  0.93154

Item-7   0.02668  0.10318  0.93133

Item-8   0.02670  0.10106  0.93228

Item-9   0.02697  0.10188  0.93122

 

The probabilities of stage-0 person are nearly 0, probabilities of stage-1 person is high on item-0 to item-4, but low on item-5 to item-9. Persons in stage-2 can answer correctly for all items.

 

Mean probabilities that a person is in each of the stages are shown as follows:

 

P(stage|person)

 

            stage-0  stage-1  stage-2

Person-0    0.77684  0.14212  0.08104

Person-1    0.77793  0.14119  0.08088

Person-2    0.77805  0.14182  0.08013

Person-3    0.77776  0.14293  0.07930

Person-4    0.77680  0.14301  0.08019

Person-5    0.77623  0.14279  0.08098

Person-6    0.77871  0.14103  0.08026

Person-7    0.16397  0.66866  0.16738

Person-8    0.16714  0.66856  0.16431

Person-9    0.16475  0.66813  0.16712

Person-10   0.16460  0.67035  0.16505

Person-11   0.16773  0.66397  0.16830

Person-12   0.16798  0.66553  0.16648

Person-13   0.16112  0.67423  0.16465

Person-14   0.08208  0.14140  0.77652

Person-15   0.08016  0.13770  0.78214

Person-16   0.08116  0.14124  0.77759

Person-17   0.08011  0.13994  0.77995

Person-18   0.07980  0.13745  0.78274

Person-19   0.08032  0.14088  0.77880

Person-20   0.08126  0.13986  0.77888

 

The probabilities for each person are adequately estimated. That is, person-0 to person-6 are estimated more probably to be in stage-0, person-7 to person-13 in stage-1, and person-14 to person-20 in stage-2.

 

The results in this website suggests that stage theory can be easily applied to real data, and statistically analyzed using Bayesian method

 

Visit this website for a sample script in PyMC3.

 

Reference

Levy, R. & Mislevy, R. J. (2016). Bayesian psychometric modeling. CRC Press

Okamoto, Y gItem Response Theory with Latent Classesh, Faculty of Integrated Arts and Social Sciences journal, 24, 103-107, 2013. Japan Womenfs University. (Click on http://id.nii.ac.jp/1133/00001684/)

 

 

Up