python用pystan貝葉斯IRT模型擬合Rasch模型分析學(xué)生考試問(wèn)題數(shù)據(jù)
原文鏈接:http://tecdat.cn/?p=26769
原文出處:拓端數(shù)據(jù)部落公眾號(hào)
由于某大學(xué)學(xué)生人數(shù)過(guò)多,助教不足,因此有必要對(duì)期中考試給每個(gè)學(xué)生的題目數(shù)量施加五道題的限制。所有必須使用的問(wèn)題必須來(lái)自大約 400 個(gè)預(yù)先批準(zhǔn)的問(wèn)題的測(cè)試庫(kù)。 50% 的問(wèn)題可以在期中使用。這項(xiàng)數(shù)據(jù)驅(qū)動(dòng)研究的目標(biāo)是找到應(yīng)該從考試生成算法中排除的問(wèn)題,以提供班級(jí)中最有意義的學(xué)生排名。
數(shù)據(jù)分析
動(dòng)機(jī)
數(shù)據(jù)由 409,520 個(gè)觀察值、12839 名學(xué)生和 391 個(gè)問(wèn)題組成。這意味著最多可以從測(cè)試庫(kù)中排除 195 個(gè)問(wèn)題。在我開(kāi)始任何數(shù)據(jù)分析之前,必須為分析準(zhǔn)備數(shù)據(jù)。首先,我檢查是否有任何學(xué)生沒(méi)有正確回答或所有學(xué)生都正確回答的問(wèn)題。如果所有學(xué)生都答錯(cuò)了一道題,說(shuō)明題目太簡(jiǎn)單了。反之,如果所有學(xué)生都答對(duì)了一道題,則說(shuō)明這道題太難了。無(wú)論哪種情況,這些問(wèn)題都不會(huì)對(duì)中期結(jié)果造成任何差異。因此,我可以立即刪除這些問(wèn)題。
#檢查是否有問(wèn)題太容易
gros = databy(['question_id']).mean()
proect = groions[['correct']].sores(by='correct')
prot.head()

#檢查是否有問(wèn)題太難
prrect.tail()

從第一個(gè)表格中,我們看到?jīng)]有任何問(wèn)題一個(gè)學(xué)生也沒(méi)回答正確。但是,通過(guò)查看第二張表,我們看到每個(gè)人都正確回答了一個(gè)問(wèn)題,因此我們從數(shù)據(jù)集中刪除了該問(wèn)題。
daa = da.loc[dta['qu_id'] != 12665]
在考慮使用機(jī)器學(xué)習(xí)或統(tǒng)計(jì)方法時(shí),我最初的想法是找到回答中差異最大的問(wèn)題,并將回答中相關(guān)性高的問(wèn)題分組(即,正確回答問(wèn)題 A 的學(xué)生也傾向于正確回答 B 題)。我意識(shí)到這種方法行不通,因?yàn)榫哂懈叻讲畹膯?wèn)題并不一定意味著它是創(chuàng)建有意義的學(xué)生等級(jí)的好問(wèn)題(例如,它可能是每個(gè)人都猜測(cè)的難題)。此外,我還必須考慮每個(gè)學(xué)生的能力差異。這讓我想到了潛在變量建模,其中潛在變量將是每個(gè)學(xué)生的能力和每個(gè)問(wèn)題的難度,這就是我如何找到 IRT 模型的。

其中 θj是學(xué)生的能力,βi是問(wèn)題的難度,αi是問(wèn)題區(qū)分弱學(xué)生和強(qiáng)學(xué)生的程度。
并非每個(gè)學(xué)生都會(huì)回答數(shù)據(jù)集中的每個(gè)問(wèn)題。這使得標(biāo)準(zhǔn)回歸方法變得困難,但貝葉斯方法在這種情況下仍然可以很好地工作。我使用 pystan 在數(shù)據(jù)上擬合 2 參數(shù) Rasch 模型,然后對(duì) αi 參數(shù)進(jìn)行后驗(yàn)。之后,我保留 196 個(gè)具有最大平均后驗(yàn) α?值的問(wèn)題。這些問(wèn)題最能區(qū)分理解材料的學(xué)生和不理解材料的學(xué)生。不幸的是,我無(wú)法驗(yàn)證我對(duì)原始數(shù)據(jù)的分析,因?yàn)槲也恢勒鎸?shí)的參數(shù)值。但是,如果我使用已知參數(shù)模擬數(shù)據(jù)并使用這種貝葉斯 rasch 模型方法恢復(fù)這些參數(shù),那么我可以自信地在真實(shí)給定數(shù)據(jù)上使用模型得出推論。
模擬研究
對(duì)于模擬,測(cè)試庫(kù)中將有 400 個(gè)問(wèn)題,只有 500 名學(xué)生。學(xué)生回答的問(wèn)題數(shù)量是一個(gè)隨機(jī)正態(tài)變量,平均值為 100,標(biāo)準(zhǔn)差為 10。這是為了模擬在實(shí)際數(shù)據(jù)集中,每個(gè)學(xué)生回答的問(wèn)題數(shù)量不同。判別參數(shù) αj 取自均值為 0.5 且形狀為 1 的對(duì)數(shù)正態(tài)分布,難度參數(shù) βj 取自均值為 0 且標(biāo)準(zhǔn)差為 5 的正態(tài)分布,學(xué)生能力參數(shù) θj 取自標(biāo)準(zhǔn)正態(tài)分布。結(jié)果變量(學(xué)生是否正確回答問(wèn)題)是隨機(jī)伯努利變量,成功概率為每個(gè)學(xué)生-問(wèn)題對(duì)的 αi(θj-βi) 的逆對(duì)數(shù)。
nutions = 400
nuents = 500
#為400個(gè)試題生成區(qū)分度和難度參數(shù)
aphas = scipy.stvs(s=1, loc=0.5, size=num_questions)
beas = scim.rvs(scale=5, size=num_questions)
#為500名學(xué)生生成能力參數(shù)
theas = scinorm().rvs(ntudents)
#挑選學(xué)生回答的問(wèn)題;每個(gè)學(xué)生隨機(jī)回答30個(gè)左右的問(wèn)題
ag = 100 #回答的平均問(wèn)題
sd = 10
qet = np.rint(scrm.rvs(loc=a, sce=sd, size=umdns)).asye(int)
nu_bs = np.sum(quton_c_tdent)
stdnm = np.reat(npange(1,np.sze(qsdt)+1), quets_ac_sdnt)
qeoncumn = np.empty(numbs)
rrecumn = np.empty(nm_os)
prenix = 0 #追蹤我們正在更新的索引
for i in rage(n_ses):
nq = quunt[i] #學(xué)生i的問(wèn)題數(shù)
quere = pre(nins, nq, ?relce=Flse) #隨機(jī)選擇每個(gè)學(xué)生回答的問(wèn)題
s_lm[pn:pr_dex + nq] = qeed
p = siypcs[] * (hta[i] - ets[qioed]))
coom[pre_ie:rnx + nq] = cisnlrs(p)
pesn_idx = ren_idx + nq
qsnmn = (qti_lmn + 1).ayp(int) #pystan的索引從1開(kāi)始
coc_umn = cotcon.atype(int)
在我們模擬數(shù)據(jù)并正確格式化以便 pystan 可以處理它之后,我們將數(shù)據(jù)傳遞到我們將用于真實(shí)數(shù)據(jù)的模型中。
int<lower=1> I; // # 問(wèn)題
int<lower=1> J; // # 人數(shù)
int<lower=1> N; // # 觀察值
int<lower=1, upper=I> i[N]; // n的問(wèn)題
ctor<lower=0>[I] alp; // 項(xiàng)目i的鑒別力
beta; // 項(xiàng)目i的難度
apa ~ lognormal(0.5,1);
bea ~ normal(0,10);
tea ~ normal(0,1);
y ~ brnollilogit(alha[ii] .* (tea[jj] - bta[ii]))。
從后驗(yàn)分布采樣后,我檢查參數(shù)的后驗(yàn)均值。如果模型在恢復(fù)參數(shù)方面做得很好,則參數(shù)的后驗(yàn)均值與實(shí)際參數(shù)值的散點(diǎn)圖應(yīng)以恒等線為中心。
sm = pystan(model_code=lrte) #pystan model
#index 9是實(shí)際后驗(yàn)參數(shù)值出現(xiàn)在數(shù)據(jù)幀中的地方
#我們希望得到后驗(yàn)抽樣的平均值
meaahas = preaha.man()[9:].asaix()
plt.figure()
plt.scatter(alha, meanphas)
#為beta繪制圖表
lntrt = bamn()
plt.figure()
plt.scar(beas, men_eas)
#為thetas繪制圖表
linSart = hets.n()
liend= thtas.max()



上面的 3 個(gè)散點(diǎn)圖表明,雖然貝葉斯 2 參數(shù) IRT 模型方法成功地恢復(fù)了學(xué)生的能力 θ,但它未能恢復(fù) β 和 α 參數(shù)。對(duì)于 β 參數(shù),當(dāng) β 介于 -5 和 5 之間時(shí),預(yù)測(cè) βs 的后驗(yàn)均值大致等于真實(shí)值。對(duì)于較大的 β 值,后驗(yàn)圖似乎被放大了。我們最關(guān)心的參數(shù)集 α 參數(shù)的散點(diǎn)圖似乎大致沿著恒等線下降,除了一個(gè)異常平坦的點(diǎn),其中 αs 的后驗(yàn)均值略大于 3,而與真實(shí)值無(wú)關(guān)。雖然這種方法沒(méi)有像我們希望的那樣準(zhǔn)確地推斷出歧視參數(shù),但它做得還不錯(cuò)。鑒于模型擬合選項(xiàng)的數(shù)量有限和時(shí)間限制,我們繼續(xù)采用這種方法。由于實(shí)際數(shù)據(jù)集中每個(gè)問(wèn)題的數(shù)據(jù)點(diǎn)更多,因此模型推理應(yīng)該會(huì)有所改進(jìn)。
模型擬合
接下來(lái),我將貝葉斯模型應(yīng)用于實(shí)際給定的數(shù)據(jù)集。首先,我檢查每個(gè)學(xué)生看到了多少問(wèn)題,以及每個(gè)問(wèn)題有多少學(xué)生回答了問(wèn)題。此外,如果一個(gè)問(wèn)題沒(méi)有被多次回答(< 50),那么很難推斷出該問(wèn)題的難度。在這些情況下,刪除與這些學(xué)生和問(wèn)題相關(guān)的觀察可能是有意義的。
qutount = dta.grby(['quesid']).sie() #得到回答每個(gè)問(wèn)題的學(xué)生的數(shù)量
quess_50 = quescount[quesnt < 50] #獲得少于50名學(xué)生的問(wèn)題的ID

在我淘汰回答少于 20 個(gè)問(wèn)題的學(xué)生之前,我會(huì)檢查那些回答較少問(wèn)題的學(xué)生是否比那些回答較多問(wèn)題的學(xué)生弱。我可以通過(guò)比較 2 個(gè)不同人群正確回答的問(wèn)題比例分布來(lái)粗略檢查這一點(diǎn)。從下面的直方圖中,直方圖的形狀似乎相同,因此我們可以繼續(xù)過(guò)濾掉回答少于 20 個(gè)問(wèn)題的學(xué)生。
useont = ata.goupy(['usr_id']).size()
usr20 = use_cout[erut_cot >= 20] #獲得回答20個(gè)問(wèn)題或以上的學(xué)生的id


#過(guò)濾掉沒(méi)有足夠觀察力的問(wèn)題和用戶
ata = da.oc[data'urid'].is(uer_r_20.ie)]
ata =datoc[~dat['qtion_i'].i(qesonles_5)]
過(guò)濾掉一些問(wèn)題和學(xué)生后,我們剩下 378 個(gè)問(wèn)題和 9785 個(gè)學(xué)生,總共 357,352 個(gè)觀察值。接下來(lái),我將問(wèn)題的 ID 和學(xué)生的 ID 分別映射到集合,因?yàn)?pystan 需要這些標(biāo)識(shí)符是從1開(kāi)始的連續(xù)正整數(shù)。然后我們可以將數(shù)據(jù)傳遞到pystan中的模型中。
# 將問(wèn)題的ID映射到1,2,...。
uni = np.uqu(daa['qustonid'])
newid1 = p.arng(1,en(niqq)+)
qdit dict((unq_q, ne_id)
dta['_id = daa.pply(lmbdaro: qict[ow.qesion_i], xs=1)
# 將學(xué)生ID映射到1,2,...
uiqu = n.uiqe(dat['use_d'])
ne_2 = np.ange1,len(uq_)+1)
dit = dit(zp(unq_, nw_i2))
aa['uid'] = daa.pp(lama ow: uit[row.ser_], xis=)
我們現(xiàn)在可以將數(shù)據(jù)傳遞到 pystan 以檢索 αj 的后驗(yàn)圖。
# 將數(shù)據(jù)格式化后傳入pystan
# 將模型與真實(shí)數(shù)據(jù)進(jìn)行擬合
ralfi = s.salng(ata=rtdata, ite=100chais=4, sampe_fil='Rel_Draws, njs4,
ctol='adpt_dela' 0.75 'max_tredeph' ?15})
#得到196個(gè)具有最高歧視參數(shù)的問(wèn)
alandi = (al_st)rsrt()[:196] + 1
#反向映射以獲得問(wèn)題的原始ID
imp = v: kfor k,v in qict.tems(ices)
#找到問(wèn)題庫(kù)和問(wèn)題清單之間的區(qū)別
qutino_rop= [q fo q in queston_bak ifq not in qeonep
pin(quesiono_dro)

上面顯示了基于貝葉斯 2 參數(shù) IRT 模型方法要丟棄的 195 個(gè)問(wèn)題的 ID。由于這些問(wèn)題在區(qū)分理解材料和不理解材料的學(xué)生方面做得最差,刪除這些問(wèn)題將使用測(cè)試生成算法提供最有意義的排名。
限制和未來(lái)的工作
雖然貝葉斯 2 參數(shù) IRT 模型方法能夠有效地推斷學(xué)生的能力,但它幾乎不能推斷出問(wèn)題的難度或區(qū)分值。此外,IRT 模型假設(shè)問(wèn)題是可交換的,而實(shí)際上它們是連續(xù)相關(guān)的(例如,學(xué)生在回答更多問(wèn)題時(shí)可能會(huì)感到疲勞)。違反這一假設(shè)可能會(huì)影響分析結(jié)果的有效性。

最受歡迎的見(jiàn)解
1.matlab使用貝葉斯優(yōu)化的深度學(xué)習(xí)
2.matlab貝葉斯隱馬爾可夫hmm模型實(shí)現(xiàn)
3.R語(yǔ)言Gibbs抽樣的貝葉斯簡(jiǎn)單線性回歸仿真
4.R語(yǔ)言中的block Gibbs吉布斯采樣貝葉斯多元線性回歸
5.R語(yǔ)言中的Stan概率編程MCMC采樣的貝葉斯模型
6.R語(yǔ)言貝葉斯Poisson泊松-正態(tài)分布模型分析職業(yè)足球比賽進(jìn)球數(shù)
7.R語(yǔ)言使用貝葉斯 層次模型進(jìn)行空間數(shù)據(jù)分析
8.R語(yǔ)言隨機(jī)搜索變量選擇SSVS估計(jì)貝葉斯向量自回歸(BVAR)模型
9.matlab貝葉斯隱馬爾可夫hmm模型實(shí)現(xiàn)