読者です 読者をやめる 読者になる 読者になる

アルゴリズム忘備録

競技プログラミングとかデータ分析とか

IRT + Stan でらくらくスコアリング

テスト問題を作成する時に困るのが配点です。できれば問題の難易度に応じて配点を決めたいのですが、問題の難易度の推定は意外と難しいです。そこでTOEICなんかではIRTという方法が使われています。

 

数理モデルはWikipeida当たりに詳しいのでそちらを参考にしてください。

項目応答理論 - Wikipedia

簡単にいえば、能力の高い人ほど難易度の難しい問題が解ける確率が上がる、というモデルです。そこで問題の難易度を(Wikipediaの記号で言えば)θ[i], 回答者の能力をb[i]として正解または不正解の2値の確率がロジスティック分布するというモデルになります。(ただこれだけだと若干扱いにくいので、識別率等のパラメータも入っていますが、詳細は略)

 

さて、モデル化できたとは言えパラメータがO(問題の数+回答者の数)だけあるものですので、解析的に計算することが困難です。TOEICはどうやってるのか知りませんが、例えばStan等でパラメタ推定するという方法がお手軽です。なんとRstanでは公式にExampleとしてIRTのモデルが配布されており、これを使うだけで簡単にIRTのパラメタが推定できます。

github.com

 

ただこのモデルはIndexがjjやkkになっているなど、若干扱いにくいモデルな気もするので、私は下記のように書き換えました。

 

data {
  int<lower=1> J; // numbrt of students
  int<lower=1> K; // number of questions
  int<lower=0, upper=1> y[J, K]; // correctness
}

parameters {
  real delta;
  real alpha[J];
  real beta[K];
  real log_gamma[K];
  real<lower=0> sigma_alpha;
  real<lower=0> sigma_beta;
  real<lower=0> sigma_gamma;
}

model {
  alpha ~ normal(0, sigma_alpha);
  beta ~ normal(0, sigma_beta);
  log_gamma ~ normal(0, sigma_gamma);
  delta ~ normal(.75,1);

  for (j in 1:J) {
    for (k in 1:K) {
      y[j, k] ~ bernoulli_logit(exp(log_gamma[k]) * (alpha[j] - beta[k] + delta));
    }
  }
}

 

 あとは正解1、不正解0のmatrix dataを作成し、突っ込んで見るだけでIRTが計算できます。すごいですね。

 

mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff Rhat
delta 0.77 0.13 1.02 -1.56 0.10 0.78 1.51 2.59 63 1.03
alpha[1] -87.02 32.98 301.56 -279.73 -124.91 -62.00 -27.32 420.90 84 1.02
alpha[2] -80.98 36.83 361.77 -351.74 -114.98 -62.63 -30.84 471.05 96 1.01
alpha[3] 158.82 51.26 418.68 -267.69 61.02 100.14 173.25 804.92 67 1.03
alpha[4] -19.90 66.68 462.98 -716.13 11.47 36.05 64.54 305.10 48 1.07
alpha[5] 67.11 105.82 410.92 -797.50 38.92 97.84 191.13 416.25 15 1.17
alpha[6] 21.77 41.08 192.35 -89.26 -32.97 -9.99 9.61 597.90 22 1.16
alpha[7] -48.15 47.62 300.77 -527.20 -35.31 -12.04 8.99 141.71 40 1.07
alpha[8] 212.27 100.64 668.94 -172.63 56.55 112.28 180.84 1601.09 44 1.07
alpha[9] -56.79 49.54 332.28 -831.35 -41.41 -12.59 6.93 150.69 45 1.07
alpha[10] -170.93 43.87 373.47 -574.44 -212.10 -124.33 -69.93 198.09 72 1.03
beta[1] -29.03 13.71 184.55 -207.26 -65.95 -36.52 -9.09 258.44 181 1.02
beta[2] -97.16 17.89 231.61 -529.99 -127.07 -83.46 -38.86 167.99 168 1.02
beta[3] 80.57 23.90 229.00 -92.39 24.41 53.18 84.58 500.60 92 1.05
beta[4] 39.48 72.63 283.84 -846.13 -7.68 34.73 131.06 519.27 15 1.17
beta[5] -10.98 38.04 314.10 -865.74 0.98 13.90 47.77 228.96 68 1.05
beta[6] -8.32 13.52 309.31 -338.01 -79.71 -17.03 25.00 459.28 523 1.01
beta[7] -2.44 26.96 282.07 -365.96 -79.18 -27.74 45.35 470.06 109 1.03
log_gamma[1] -27.75 36.10 123.63 -398.36 -2.95 0.47 6.00 23.18 12 1.39
log_gamma[2] -24.08 32.27 116.86 -418.57 -5.61 0.50 11.56 34.16 13 1.39
log_gamma[3] -28.17 42.85 156.55 -501.14 -1.58 3.66 12.22 81.95 13 1.38
log_gamma[4] -62.23 52.16 178.41 -627.40 -37.70 -19.96 -6.41 -2.47 12 1.34
log_gamma[5] -19.78 35.04 117.68 -417.28 -0.93 5.79 17.76 38.68 11 1.46
log_gamma[6] -52.48 41.10 143.12 -461.24 -28.32 -15.49 -8.27 -4.44 12 1.36
log_gamma[7] -52.80 40.43 166.72 -525.88 -24.72 -14.55 -7.90 -3.69 17 1.27
sigma_alpha 215.69 110.14 448.73 23.63 64.75 127.21 186.27 1211.27 17 1.23
sigma_beta 176.98 76.93 318.87 14.71 54.82 93.90 165.96 1139.51 17 1.27
sigma_gamma 72.53 57.55 180.64 4.34 11.96 19.92 34.37 677.08 10 1.57
lp__ -127.04 8.90 24.62 -200.26 -130.20 -121.82 -115.55 -88.48 8 2.44 

 

このalpha[n]ってのが各人の能力値です。特にmean(平均値)の値。

これを使ってテストの点数が問題の難易度込みで(事前に難易度を決めなかったにも関わらず)決定できます。