Up

項目反応理論における信頼性係数

PrecisionStability/ConsistencyPredictive Powerの推定

 

項目反応理論における信頼性係数の3つの指標、precisionstability/consistencypredictive power、の推定例がOkamoto (2017) で報告されている。各指標はシミュレーションによって推定されているが、シミュレーションでは以下の設定が行われている。

 

:   テスト項目i, の回答。回答は2値以上のカテゴリでよい。

:   p, に実施されたテスト項目の組。 は、実施された j番目の項目を表す。実施項目のセットが固定されているとき、 は人に依らず同じ項目セットであり、通常の質問紙法による心理尺度の場合はこの方法になっている。実施項目が適応的に選ばれる場合、 は回答者の回答パターンに応じて決まる。

:    pの特性値の真値。

:     真値 の推定値。

 

上の設定は、次のダイアグラム(1)によって表される。

ダイアグラム(1)の下で、信頼性の3つの指標が以下のように求められる。

 

Precision.  これはよく知られた信頼性の数学的定義である。ベイズ分析を採用した場合の定義として次式(2)を用いる。

ここで、    は、 の事後分布と事前分布の分散である。, の平均値は次式(3)で与えられる。

信頼性係数 precision の推定値を求めるPythonスクリプトは この後半に上げられている。

 

Stability (Consistency).  これは、同じ質問紙あるいはテストを独立に2回受けたときの2つの推定値の間の相関係数で与えられるものである。すなわち、回答者は、ダイアグラム(1)の回答結果と、次のダイアグラム(1‘)による回答結果から得られる2つの推定値が与えられる。

2つの結果は、  で表され、それぞれに対応して2つの推定値   が得られる。尺度の stability は、  の相関係数(4)

で与えられる。Samejima (1994) は相関係数 (4) を最尤法において論じている。

信頼性係数stability (consistency) を求めるPythonスクリプトは、 後半に上げられている。

 

Predictive Power.  真値 の推定値 による予測は次式(5)

で表される。このときの予測力はモデル(5)の決定係数 で与えられ、これは2つの変数  の相関係数の2乗(6)

で与えられるものである。

推定値 を従属変数、真値を独立変数としたときの関係は次式(7)で表される。

モデル(7)の決定係数はモデル(5)のものと同じ値(6)である。決定係数(6)は、真値と推定値 のモデル(5)あるいは(6)における関係の強さを表すものである。

信頼性係数predictive powerの推定値を求めるPythonスクリプトは、 この後半.に上げられている。

 

本ウェブサイトのシミュレーションにおける項目反応理論の基本モデル

項目数を とし、各項目の回答カテゴリ数が  個であるとする。回答カテゴリを 1 から  の整数値で表す。項目 への回答を で表す。このとき、である。段階反応モデル(Samejima, 1969) あるいは Thurstonian モデルと呼ばれている次式(8)を設定する。

ここで、

である。はカテゴリ境界を表し、次式

を満たすものである。

モデル(8)に対するStanスクリプトEstTheta.stanをリスト1に示す。回答パターン に対して、 の事後分布を求めるものである。

 

リスト1. の事後分布を求めるStan スクリプト EstTheta.stan

data {

    int K;

    int Nitm;

    real C[K - 1];

    real<lower = 0.0> a[Nitm];

    real b[Nitm];

    int<lower = 1, upper = K> X[Nitm];

}

parameters {

    real theta;

}

transformed parameters {

    vector[K] p[Nitm];

    for (i in 1:Nitm){

        p[i][K] = inv_logit(1.7 * a[i] * (theta - b[i] - C[K - 1]));

        p[i][1] = 1.0 - inv_logit(1.7 * a[i] * (theta - b[i] - C[1]));

        if (K > 2){

            for (k in 2:(K - 1)) {

                p[i][k] = inv_logit(1.7 * a[i] * (theta - b[i] - C[k - 1]))

                            - inv_logit(1.7 * a[i] * (theta - b[i] - C[k]));

            }

        }

    }

}

model {

    theta ~ normal(0.0, 1.0);

    for (i in 1:Nitm)

        X[i] ~ categorical(p[i]);

}

 

このStanスクリプトEstTheta.stanを用いて、M個の項目からなる尺度の信頼性をモデル(8)に基づくシミュレーションににより信頼性係数が求められる。

以下の例では、項目数がM=5で、各項目のパラメータおよびカテゴリ境界が次のようである場合が想定されている。カテゴリ数は2である。

この設定は、Pythonスクリプトでは以下のようにコーディングされている。

Nitems = 5                                 #    Number of items

X = [1, 1, 1, 1, 1]                        #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]              #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]            #    Difficulty parameters

K = 2                                      #    Number of response categories

C = [0.0]                                  #    Category boundaries

もちろん、上の設定以外の場合についても、変数 Nitems, X, a, b, Kおよび Cを信頼性係数を求める項目セットに合わせて設定すれば、それに対する信頼性係数が求められる。

 

信頼性係数Precisionの推定

信頼性係数Precisionは、ダイアグラム (1)および式 (2)(3) を用いて、リスト2のPythonスクリプトによって求めることができる。

リスト 2. 信頼性係数 precision 推定のためのPythonスクリプト。

import pystan

from pystan import StanModel

import pickle

import random

import math

import matplotlib.pyplot as plt

 

def icc(t, a, b, c):

    return 1.0 / (1.0 + math.exp(-1.7 * a * (t - b - c)))

 

def CatResponse(t, a, b, c, K):

    res = 1

    v = random.random()

    while True:

        if v > icc(t, a, b, c[res - 1]):

            break

        res += 1

        if res >= K:

            break

    return res

 

def calcVar( L ):

    n = len(L)

    sum = 0.0

    for v in L:

        sum += v

    mean = sum / n

    ssum = 0.0

    for v in L:

        ssum += (mean - v) ** 2.0

    return ssum / (n - 1.0)

 

Nitems = 5                                 #    Number of items

X = [1, 1, 1, 1, 1]                        #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]              #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]            #    Difficulty parameters

K = 2                                      #    Number of response categories

C = [0.0]                                  #    Category boundaries

#   K = 7

#   C = [-2.0, -1.0, -0.25, 0.25, 1.0, 2.0]

 

Data = {'K': K, 'Nitm': Nitems,  'C': C, 'a':a, 'b': b, 'X': X}

 

sm = StanModel(file = 'EstTheta.stan')

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

    pickle.dump(sm, f)

 

L_theta = []

L_precision = []

n_step = 1000

for step in range(n_step):

    if (step % 5 == 0):

        print("\nstep = {0}/{1}".format(step, n_step))

    t = random.gauss(0.0, 1.0)

    for i in range(Nitems):

        X[i] = CatResponse(t, a[i], b[i], C, K)      

       

    sm = pickle.load(open('model.pkl', 'rb'))

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

    theta = fit['theta']

    var_theta = calcVar(theta)

 

    L_theta.append(t)

    L_precision.append(1.0 - var_theta)

 

sum = 0.0

for p in L_precision:

    sum += p

mean_precision = sum / len(L_precision)

 

 

plt.title("Mean precison = {0:>.3}".format(mean_precision))

plt.xlabel("theta")

plt.ylabel("precison")

plt.axis([-4.0, 4.0, 0.0, 1.0])

plt.plot(L_theta, L_precision, 'bo')

plt.show()

 

上のスクリプトを実行すると、図1のグラフが表示される。

1

 

図1のグラフは、モデル(8)において以下に示す設定に対するものである。

これは、Pythonスクリプトでは以下のようにコーディングされている。

Nitems = 5                                 #    Number of items

X = [1, 1, 1, 1, 1]                        #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]              #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]            #    Difficulty parameters

K = 2                                      #    Number of response categories

C = [0.0]                                  #    Category boundaries

 

カテゴリ数を2から7に増やした場合のコード例を次のように用意した。

K = 7

C = [-2.0, -1.0, -0.25, 0.25, 1.0, 2.0]

リスト2の該当箇所を上のコードで置き換えて実行すると、図2に示す結果が得られる。

2

 

2値項目の場合の図1の結果を図2と比較すると、項目のカテゴリ数を増やすと信頼性が格段に高くなることが判る。

 

上のPythonスクリプトとStanスクリプトは圧縮ファイルPrecision.zipにまとめた。ダウンロードして自由に利用することができる。

 

信頼性係数Stability (Consistency)の推定

信頼積係数Stability (Consistency)を、2つのダイアグラム(1) (1)によって求めるPythonスクリプトをリスト3に示す。

 

リスト 3. 信頼性係数stability (consistency)の推定Pythonスクリプト。.

import pystan

from pystan import StanModel

import pickle

import random

import math

import matplotlib.pyplot as plt

 

def icc(t, a, b, c):

    return 1.0 / (1.0 + math.exp(-1.7 * a * (t - b - c)))

 

def CatResponse(t, a, b, c, K):

    res = 1

    v = random.random()

    while True:

        if v > icc(t, a, b, c[res - 1]):

            break

        res += 1

        if res >= K:

            break

    return res

 

def calcCor(data1, data2):

    sum1 = 0.0

    sum2 = 0.0

    n = len(data1)

    for i in range(n):

        sum1 += data1[i]

        sum2 += data2[i]

    mean1 = sum1 / n

    mean2 = sum2 / n

    ssum1 = 0.0

    ssum2 = 0.0

    xsum = 0.0

    for i in range(n):

        ssum1 += (data1[i] - mean1) ** 2

        ssum2 += (data2[i] - mean2) ** 2

        xsum += (data1[i] - mean1) * (data2[i])

    return xsum / ((ssum1 * ssum2) ** 0.5)

 

Nitems = 5                         #    Number of items

X = [1, 1, 1, 1, 1]                #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]      #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]    #    Difficulty parameters

K = 2                              #    Number of response categories

C = [0.0]                          #    Category boundaries

#   K = 7

#   C = [-2.0, -1.0, -0.25, 0.25, 1.0, 2.0]

 

Data = {'K': K, 'Nitm': Nitems,  'C': C, 'a':a, 'b': b, 'X': X}

 

sm = StanModel(file = 'EstTheta.stan')

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

    pickle.dump(sm, f)

 

L_theta1 = []

L_theta2 = []

 

n_step = 1000

for step in range(n_step):

    if (step % 5 == 0):

        print('\nstep = {0}/{1}'.format(step, n_step))

    t = random.gauss(0.0, 1.0)

    for i in range(Nitems):

        X[i] = CatResponse(t, a[i], b[i], C, K)

    sm = pickle.load(open('model.pkl', 'rb'))

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

    theta = fit['theta']

    theta.sort()

    L_theta1.append(theta[int(len(theta) / 2)])

 

    for i in range(Nitems):

        X[i] = CatResponse(t, a[i], b[i], C, K)

    sm = pickle.load(open('model.pkl', 'rb'))

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

    theta = fit['theta']

    theta.sort()

    L_theta2.append(theta[int(len(theta) / 2)])

   

r = calcCor(L_theta1, L_theta2)

 

plt.title("Cor(theta1, theta2) = {0:>.3}".format(r))

plt.xlabel("theta1")             

plt.ylabel("theta2")              

plt.plot(L_theta1, L_theta2, 'bo')   

plt.show()

 

このスクリプトを実行すると、図3の結果が表示される。

図3

 

図3は、以下の項目セットに対してモデル(8)を適用して求められたものである。Figure 3 is for items, which have the following parameter values for Model (8),

この設定は、Pythonスクリプトでは以下のようにコーディングされている。

Nitems = 5                                 #    Number of items

X = [1, 1, 1, 1, 1]                        #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]              #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]            #    Difficulty parameters

K = 2                                      #    Number of response categories

C = [0.0]                                  #    Category boundaries

 

カテゴリ数を次のコードに示すように2から7に増やすと図4の結果を得る。When the number of categories is increased from 2 to 7, in this case the code concerning to the number of categories K and category boundaries C are changed to, e.g.,

K = 7

C = [-2.0, -1.0, -0.25, 0.25, 1.0, 2.0]

4

 

同じ項目セットであっても、カテゴリ数を2から7に増やしたときの信頼性係数の増加は顕著である。

信頼性係数stability (consistency)を求めるPythonスクリプトとStanスクリプトを圧縮ファイル Consistency.zipとしてまとめた。ダウウンロードして自由に利用することができる。

 

信頼性係数 Predictive Power の推定

信頼性係数predictive power をダイアグラム (1)、および式 (6) (7)を用いて求めるPythonスクリプトをリスト 4に示す。

 

リスト 4. 信頼性係数predictive powerを求めるPythonスクリプト。.

import pystan

from pystan import StanModel

import pickle

import random

import math

import matplotlib.pyplot as plt

 

def icc(t, a, b, c):

    return 1.0 / (1.0 + math.exp(-1.7 * a * (t - b - c)))

 

def CatResponse(t, a, b, c, K):

    res = 1

    v = random.random()

    while True:

        if v > icc(t, a, b, c[res - 1]):

            break

        res += 1

        if res >= K:

            break

    return res

 

def calcCoeff(x, y):

    sumx = 0.0

    sumy = 0.0

    n = len(x)

    for i in range(n):

        sumx += x[i]

        sumy += y[i]

    meanx = sumx / n

    meany = sumy / n

    sumxx = 0.0

    sumyy = 0.0

    sumxy = 0.0

    for i in range(n):

        sumxx += (x[i] - meanx) ** 2

        sumyy += (y[i] - meany) ** 2

        sumxy += (x[i] - meanx) * (y[i] - meany)

    Cxy = sumxy / n

    Sx = (sumxx / n) ** 0.5

    Sy = (sumyy / n) ** 0.5

    r = Cxy / (Sx * Sy)

    a = r * Sy / Sx

    b = -Cxy * meanx / (Sx ** 2) + meany

       

    return r, a, b

 

Nitems = 5                         #    Number of items

X = [1, 1, 1, 1, 1]                #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]      #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]    #    Difficulty parameters

K = 2                              #    Number of response categories

C = [0.0]                          #    Category boundaries

#   K = 7

#   C = [-2.0, -1.0, -0.25, 0.25, 1.0, 2.0]

 

Data = {'K': K, 'Nitm': Nitems,  'C': C, 'a':a, 'b': b, 'X': X}

 

sm = StanModel(file = 'EstTheta.stan')

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

    pickle.dump(sm, f)

 

L_theta1 = []

L_thetaTrue = []

n_step = 1000

for step in range(n_step):

    if (step % 5 == 0):

        print('\nstep = {0}/{1}'.format(step, n_step))

    t = random.gauss(0.0, 1.0)

    L_thetaTrue.append(t)

    for i in range(Nitems):

        X[i] = CatResponse(t, a[i], b[i], C, K)

    sm = pickle.load(open('model.pkl', 'rb'))

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

    theta = fit['theta']

    theta.sort()

    L_theta1.append(theta[int(len(theta) / 2)])

 

r, coeff_a, coeff_b = calcCoeff(L_thetaTrue, L_theta1)

 

min_t = L_thetaTrue[0]

max_t = min_t

n = len(L_thetaTrue)

for i in range(n):

    if min_t > L_thetaTrue[i]:

        min_t = L_thetaTrue[i]

    if max_t < L_thetaTrue[i]:

        max_t = L_thetaTrue[i]

 

regression_x = [min_t, max_t]

regression_y = [coeff_a * min_t + coeff_b, coeff_a * max_t + coeff_b]

plt.plot(regression_x, regression_y, 'b-')

 

plt.title("Predictive power = {0:>.3}\nr = {1:>.3}".format(r**2, r))

plt.xlabel("True theta")   

plt.ylabel("Est. theta")    

plt.plot(L_thetaTrue, L_theta1, 'bo')   

plt.show() 

 

上のスクリプトを実行すると図5の結果を得る。図中の右上がりの直線は回帰直線である。

5

 

図5の結果は、モデル(8)において次のパラメータ値をもつ項目セットに対して信頼性係数predictive powerを求めたものである。

このパラメータ値はPythonスクリプトにおいて以下のようにコーディングされている。

Nitems = 5                                 #    Number of items

X = [1, 1, 1, 1, 1]                        #    Responses to be set in simulation

 

a = [1.0, 1.0, 1.0, 1.0, 1.0]              #    Discrimination parameters

b = [-0.5, -0.3, 0.0, 0.3, 0.5]            #    Difficulty parameters

K = 2                                      #    Number of response categories

C = [0.0]                                  #    Category boundaries

 

項目に対する回答カテゴリ数を2から7に以下のように増やすと、図6の結果となる。

K = 7

C = [-2.0, -1.0, -0.25, 0.25, 1.0, 2.0]

6

 

同じ項目セットに対して、カテゴリ数を2から7に増やしたときの信頼性係数の増加は顕著である。

信頼性係数predictive powerを求めるPythonスクリプトとStanスクリプトを圧縮ファイルPredictive.zipにまとめた。ダウンロードして自由に利用することができる。

 

 

引用文献

Okamoto, Y. (2017).  Three Aspects of Reliability in Item Response Theory. Proceedings of the 15th Annual Conference of the Japan Association for Research on Testing、152−155

Samejima, F. (1994). Estimation of reliability coefficients using the test information function and its modifications. Applied Psychological Measurement, 18, 229-244.

 

Up