予備実験用の解答サンプルシートはこちら
第112回から適当に20問とってきたもの。
↓
https://docs.google.com/forms/d/e/1FAIpQLSfiLVA-1m7NC5SMmyi0X1ftSYJzhWuOac6kr-WMR8gKgFLWVA/viewform
shiny 上でその20問の項目反応理論(IRT)
↓
https://yfujii08.shinyapps.io/medicalexamltm/
※重要な話なので先頭にもってきました※
データを集めるわけだが、某予備校や解答収集サービスのようにセキリュティ強固なサーバーを持っているわけではなくむしろ予算 ゼ ロ 円解析なので、グーグルアンケートフォームにひたすらみなさんの善意でポチポチやってもらえれば、と思っています。
予備実験では20問、たぶん1問1分くらいかかって15−20分くらい時間を使わせてしまいます。
本番では400問あるので、受験者が1万人、上記サービスで7000人くらい入力しているらしいので、ネット宣伝と口コミで希望者・入力者を募りつつ、サーバー負荷やセキリュティ問題はgoogle 様やshiny 様に丸投げしようと思います。個人の特定はできないようにします。
※以下から本文※
医師国家試験とは、2日間(昔は3日間)にわたって400問をマークシートで解く。
そのほとんどは5択から1つ正解を選べ、だが、2つ選べや3つ選べ、計算結果を数値を塗りつぶして答えろ、1問1点の場合と3点の場合がある、A-F の6ブロックある、一般/臨床問題と必修問題の両方を合格基準を超えないといけない、禁忌肢という選んでしまったらそれだけで不合格となる問題や選択肢がある、といったレギュレーションがある。
そこで受験生は、ひたすら問題を解くわけだが、合格率90% を誇る試験で、たいていの問題は正答率100% に近かったりするわけだが、割問という「2択ないしは複数選択肢に解答が割れる」という問題がある。
これが毎年話題になる。
受験生としては、自分が答えた問題の正答が気になるので、○ECとかTECO○とか○んコレとかに解答を登録したりするわけだが、ここらでいう割問というのは、「その問題単体で見た時の、解答のばらつき」しか見ていない。
さて、項目反応理論(IRT) というのは、マルチョイ問題において、受験者個人の能力値(すべての問題への正答率を考慮している)、問題の難易度(その個々人が、どの問題を正答できて、どの問題を誤答したかという情報を考慮する)といったパラメータを定量的に推定する。
ここで、mirt パッケージにあるSAT12 という試験解答サンプルを使ってみる。SAT12 は600人32問題の解答パターンをもつ。
これを正解したかしてないかの1/0 バイナリデータにする。IRT 自体はltm パッケージを使うことにして、IRT により各問題の難しさや識別能の推定はltm 関数を、各個人の能力はfactor.scores 関数で得られる。
# 先頭の15人、8問目まで Item.1 Item.2 Item.3 Item.4 Item.5 Item.6 Item.7 Item.8 1 1 4 5 2 3 1 2 1 2 3 4 2 8 3 3 2 8 3 1 4 5 4 3 2 2 3 4 2 4 4 2 3 3 2 4 5 2 4 5 2 3 2 2 1 6 1 4 3 1 3 2 2 3 7 1 4 5 2 2 2 2 2 8 2 4 1 5 3 2 2 5 9 5 1 2 3 2 2 4 4 10 5 3 4 2 3 2 4 5 11 2 1 4 5 2 3 2 4 12 3 1 3 4 2 2 2 2 13 4 5 5 4 2 2 4 1 14 1 4 3 2 3 2 2 5 15 3 4 3 5 5 2 2 2
library(ltm) library(mirt) key <- c(1,4,5,2,3,1,2,1,3,1,2,4,2,1,5,3,4,4,1,4,3,3,4,1,3,5,1,3,1,5,4,5) # 正解 data <- key2binary(SAT12, key=key) # バイナリ化 l <- ltm(data ~ z1) # IRT ans <- t(mapply(function(z) table(factor(SAT12[,z], 1:5)), 1:ncol(SAT12))) plot(l)
32問分の難しさはこんな感じで出力される。
さて、各問題について見てみる。32問分の解答分布、正答、IRTの推定値は以下のとおりである。
cbind(round(ans/nrow(SAT12), 3), key, l$coefficients)
1 2 3 4 5 key (Intercept) z1 Item.1 0.283 0.203 0.267 0.232 0.013 1 -1.0458445 0.8018208 Item.2 0.212 0.022 0.070 0.568 0.127 4 0.4361887 1.5040666 Item.3 0.165 0.183 0.260 0.098 0.280 5 -1.1425458 1.0746489 Item.4 0.165 0.378 0.148 0.172 0.128 2 -0.5309422 0.5845126 Item.5 0.093 0.143 0.620 0.093 0.048 3 0.6044634 0.9900492 Item.6 0.160 0.582 0.107 0.043 0.108 1 -2.0509622 1.1494988 Item.7 0.025 0.760 0.007 0.190 0.017 2 1.3818932 1.0042941 Item.8 0.202 0.205 0.207 0.250 0.133 1 -1.5090070 0.6927192 Item.9 0.065 0.010 0.885 0.033 0.007 3 2.1427139 0.5328306 Item.10 0.422 0.215 0.165 0.028 0.167 1 -0.3615247 1.0086219 Item.11 0.003 0.983 0.008 0.003 0.002 2 5.2441772 1.7296232 Item.12 0.072 0.082 0.218 0.415 0.205 4 -0.3455723 0.1611497 Item.13 0.110 0.662 0.070 0.118 0.040 2 0.8507691 1.1074704 Item.14 0.723 0.027 0.108 0.022 0.117 1 1.1727517 1.0370366 Item.15 0.035 0.062 0.060 0.025 0.817 5 1.9224593 1.2930864 Item.16 0.070 0.105 0.413 0.215 0.195 3 -0.3825038 0.7263422 Item.17 0.008 0.005 0.010 0.963 0.013 4 4.1603459 1.5479738 Item.18 0.303 0.033 0.165 0.352 0.142 4 -0.8530572 1.7008815 Item.19 0.548 0.053 0.358 0.030 0.010 1 0.2363424 0.8403153 Item.20 0.012 0.002 0.105 0.873 0.007 4 2.6034887 1.5311169 Item.21 0.050 0.008 0.915 0.013 0.012 3 2.5167030 0.6058270 Item.22 0.028 0.005 0.935 0.017 0.015 3 3.4736774 1.5369172 Item.23 0.290 0.177 0.128 0.313 0.087 4 -0.8505416 0.6379289 Item.24 0.728 0.162 0.042 0.022 0.045 1 1.2673661 1.2051755 Item.25 0.240 0.170 0.375 0.065 0.142 3 -0.5674927 0.7713010 Item.26 0.020 0.227 0.030 0.262 0.460 5 -0.1728073 1.5352022 Item.27 0.862 0.093 0.012 0.020 0.010 1 2.7575590 1.9045292 Item.28 0.082 0.010 0.530 0.337 0.037 3 0.1722115 1.0711318 Item.29 0.340 0.295 0.205 0.085 0.067 1 -0.7508683 0.8350190 Item.30 0.150 0.110 0.107 0.183 0.440 5 -0.2484688 0.3855356 Item.31 0.075 0.020 0.012 0.833 0.058 4 2.7738863 2.3285203 Item.32 0.125 0.183 0.443 0.075 0.162 5 -1.6516711 0.1291500
IRTの推定値をプロットするとこうなる。
i1 <- c(10, 12, 16, 26, 30) i2 <- c(2, 17, 20, 22, 26) plot(l$coefficient,type="n") abline(v=mean(l$coefficients[i1, 1]), lty=3, col="blue", lwd=3) abline(h=mean(l$coefficients[i2, 2]), lty=3, col="green", lwd=3) text(l$coefficients[,1], l$coefficients[,2], 1:ncol(SAT12), font=2)
似たようなintercept を持つがz1 が異なる10, 12, 16, 26, 30 番の問題を取り上げてみると(青の垂直線、下図のひだり側)、いずれも割問である。しかし、赤の12番が平たい曲線なのに比べ、青の26番はいくぶん急峻な曲線である。
これは、前者が高得点者でもそんなに得点率が上昇しないのに比べて、後者はある得点水準から得点率が急上昇するので、その境界線の能力の受験者を分けるのにはよい。
12番と26番を見てみると、どちらも正答率は40%半ばであるが、問題の性能としてはずいぶん違う。26番は良問だが、12番はクソ問。
1 2 3 4 5 key (Intercept) z1 Item.10 0.422 0.215 0.165 0.028 0.167 1 -0.3615247 1.0086219 Item.12 0.072 0.082 0.218 0.415 0.205 4 -0.3455723 0.1611497 Item.16 0.070 0.105 0.413 0.215 0.195 3 -0.3825038 0.7263422 Item.26 0.020 0.227 0.030 0.262 0.460 5 -0.1728073 1.5352022 Item.30 0.150 0.110 0.107 0.183 0.440 5 -0.2484688 0.3855356
似たようなz1 を持つがintercept が異なる2, 17, 20, 22, 26 番の問題を取り上げてみると(緑の水平線、下図のみぎ側)、どれも似たような急斜面の曲線だが、左右に位置がずれている。正答率を見ると、赤の17番の問題で96%、水色の26番の問題で46%であり、みぎにいくほど正答率が低い難問である。
1 2 3 4 5 key (Intercept) z1 Item.2 0.212 0.022 0.070 0.568 0.127 4 0.4361887 1.504067 Item.17 0.008 0.005 0.010 0.963 0.013 4 4.1603459 1.547974 Item.20 0.012 0.002 0.105 0.873 0.007 4 2.6034887 1.531117 Item.22 0.028 0.005 0.935 0.017 0.015 3 3.4736774 1.536917 Item.26 0.020 0.227 0.030 0.262 0.460 5 -0.1728073 1.535202
各問題の難易度や良問具合がわかったので、次に、受験者個人の成績や能力値をどう定量化するかであるが、これはfactor.scores という関数で得られる。ここから結果を見ると、32問題の正答/誤答パターンが600人中どれくらいあったか(Obs) というデータから、z1(正規化した分布における確率点)が推定されるので、ここが自分(の解答から得られる正誤パターンにおける)の能力値(同一試験を受けた他の受験者全員をひっくるめた集団での)になる。
SAT12 データセットでは、全問正解が3人いるようである。
ここからz1 を拾ってきて横軸を定め、元のIRT 曲線に垂線を引くと、自分の能力で各問題をどれくらいの確率で正答できたのかが確率的にわかる。
f <- factor.scores(l) f$score.dat
Item.1 Item.2 Item.3 Item.4 Obs Exp z1 se.z1 1 0 0 0 0 1 7.320352e-07 -1.125597 0.3501032 2 0 0 0 0 1 1.192118e-05 -1.035763 0.3510456 3 0 0 0 0 1 7.614205e-06 -1.268032 0.3503369 4 0 0 0 0 1 2.158900e-04 -1.578284 0.3585213 5 0 0 0 0 1 1.354704e-03 -2.044771 0.3858258 6 0 0 0 0 1 7.785685e-06 -1.299507 0.3506911 7 0 0 0 0 1 2.653074e-04 -1.303414 0.3507428 8 0 0 0 0 1 9.714099e-05 -1.137476 0.3500392 9 0 0 0 0 1 2.220848e-05 -1.500034 0.3555113 10 0 0 0 0 1 2.611964e-04 -1.573319 0.3583131 . . . 598 1 1 1 1 3 4.027146e-02 2.590108 0.6140229 ← 全問正解が Obs = 3
データはどう集めるか問題があるが、実は某サービスが始まったときにデータを打診したらゴニョゴニョがあったので今回の解析を断念していたが、google 様とshiny 様のお力を借りて出来そう、と思い立ったのでネットで宣伝してN数稼げたらいいなあ…と思う。冒頭に書いた。