tristanz / OpenIRT (http://people.fas.harvard.edu/~tzajonc/openirt.html)

Bayesian and Maximum Likelihood Estimation of Item Response Theory (IRT) Models

Clone this repository (size: 589.9 KB): HTTPS / SSH
$ hg clone http://bitbucket.org/tristanz/openirt
commit 37: 0d32afb3521b
parent 36: 4e35255dd116
branch: default
tags: tip
Fixed 10.5 OSX compile issue
Tristan Zajonc / tristanz
7 months ago
OpenIRT / Stata / naep.do
    #   Introduced
1
12cc7127cb73
* Example code using OpenIRT
2
12cc7127cb73
3
12cc7127cb73
* Install:
4
3e5f3f33ee42
cap program drop openirt
5
eaff035c689f
net install http://www.people.fas.harvard.edu/~tzajonc/stata/openirt/openirt, force
6
3e5f3f33ee42
7
3e5f3f33ee42
clear
8
3e5f3f33ee42
set mem 50m
9
3e5f3f33ee42
10
3e5f3f33ee42
* Save 12 NAEP items locally
11
3e5f3f33ee42
sysuse naep_items, clear
12
3e5f3f33ee42
save naep_items, replace
13
3e5f3f33ee42
count
14
3e5f3f33ee42
15
12cc7127cb73
* Easier to mix and match with c=0 for 2pl
16
12cc7127cb73
recode c (.=0)
17
12cc7127cb73
18
12cc7127cb73
** DEMO 1: Item characteristic curves
19
12cc7127cb73
20
12cc7127cb73
* 2PL ICC (row 3)
21
12cc7127cb73
twoway (function 1/(1+exp(-1.7*a[3]*(x-b[3]))), range(-4 4)), ///
22
12cc7127cb73
	xtitle("Theta") ytitle("P(X=1|Theta)") title("Item Characteristic Curve")
23
12cc7127cb73
24
12cc7127cb73
* overlay two ICCs
25
12cc7127cb73
twoway (function 1/(1+exp(-1.7*a[3]*(x-b[3]))), range(-4 4)) ///
26
12cc7127cb73
	(function 1/(1+exp(-1.7*a[4]*(x-b[4]))), range(-4 4)), ///
27
12cc7127cb73
	xtitle("Theta") ytitle("P(X=1|Theta)") title("Item Characteristic Curve") ///
28
12cc7127cb73
	legend(order(1 "Item 16" 2 "Item 17"))
29
12cc7127cb73
	
30
12cc7127cb73
* 2pl and 3PL curve
31
12cc7127cb73
twoway (function 1/(1+exp(-1.7*a[3]*(x-b[3]))), range(-4 4)) ///
32
12cc7127cb73
	(function c[1] + (1-c[1])/(1+exp(-1.7*a[1]*(x-b[1]))), range(-4 4)), ///
33
12cc7127cb73
	xtitle("Theta") ytitle("P(X=1|Theta)") title("Item Characteristic Curve") ///
34
12cc7127cb73
	legend(order(1 "Item 16" 2 "Item 12"))
35
12cc7127cb73
36
12cc7127cb73
** Demo 2: Item information curves
37
12cc7127cb73
38
12cc7127cb73
* 2PL IIC
39
12cc7127cb73
local i = 3
40
12cc7127cb73
local iic2pl "(1.7*a[`i'])^2*(1/(1+exp(-1.7*a[`i']*(x-b[`i']))))*(1-(1/(1+exp(-1.7*a[`i']*(x-b[`i'])))))"
41
12cc7127cb73
twoway (function `iic2pl', range(-4 4)), ///
42
12cc7127cb73
	xtitle("Theta") ytitle("I(Theta)") title("Item Information Curve")
43
12cc7127cb73
44
12cc7127cb73
* 3PL IIC
45
12cc7127cb73
local i = 2
46
12cc7127cb73
local p "(c[`i']+(1-c[`i'])/(1+exp(-1.7*a[`i']*(x-b[`i']))))"
47
12cc7127cb73
local iic3pl "((1.7*a[`i'])^2*(1-`p')/`p')*((`p'-c[`i'])/(1-c[`i']))^2"
48
12cc7127cb73
twoway (function `iic3pl', range(-4 4)), ///
49
12cc7127cb73
	xtitle("Theta") ytitle("I(Theta)") title("Item Information Curve")
50
12cc7127cb73
51
12cc7127cb73
* Multiple graphs
52
12cc7127cb73
forvalues i = 1/9 {
53
12cc7127cb73
	local title = "Item " + string(id[`i'])
54
12cc7127cb73
	local p "(c[`i']+(1-c[`i'])/(1+exp(-1.7*a[`i']*(x-b[`i']))))"
55
12cc7127cb73
	local iic3pl "((1.7*a[`i'])^2*(1-`p')/`p')*((`p'-c[`i'])/(1-c[`i']))^2"
56
12cc7127cb73
	twoway (function `iic3pl', range(-5 5)), ///
57
12cc7127cb73
		xtitle("Theta") ytitle("I(Theta)") title("`title'")
58
12cc7127cb73
	graph save tmp`i', replace
59
12cc7127cb73
}
60
12cc7127cb73
graph combine tmp1.gph tmp2.gph tmp3.gph tmp4.gph tmp5.gph tmp6.gph tmp7.gph tmp8.gph tmp9.gph, ycommon xcommon
61
12cc7127cb73
62
12cc7127cb73
* Test information
63
12cc7127cb73
replace c = 0 if c==.
64
12cc7127cb73
local tif "0"
65
12cc7127cb73
forvalues i = 1/12 {
66
12cc7127cb73
	local p "(c[`i']+(1-c[`i'])/(1+exp(-1.7*a[`i']*(x-b[`i']))))"
67
12cc7127cb73
	local iic3pl "((1.7*a[`i'])^2*(1-`p')/`p')*((`p'-c[`i'])/(1-c[`i']))^2"
68
12cc7127cb73
	local tif "`tif'+`iic3pl'"
69
12cc7127cb73
}
70
12cc7127cb73
local se "1/sqrt(`tif')"
71
12cc7127cb73
twoway (function `tif', range(-4 4)) /// 
72
12cc7127cb73
	(function `se', range(-4 4) yaxis(2)), ///
73
12cc7127cb73
	xtitle("Theta") ytitle("I(Theta)") title("Test Information") ytitle("Standard Error", axis(2)) ///
74
12cc7127cb73
	legend(order(1 "Test Information" 2 "Expected Standard Error"))
75
12cc7127cb73
76
12cc7127cb73
** Demo 3: Test characteristic curve
77
12cc7127cb73
replace c = 0 if c==.
78
12cc7127cb73
local tcc "0"
79
12cc7127cb73
forvalues i = 1/12 {
80
12cc7127cb73
	local p "(c[`i']+(1-c[`i'])/(1+exp(-1.7*a[`i']*(x-b[`i']))))"
81
12cc7127cb73
	local tcc "`tcc'+`p'/12"
82
12cc7127cb73
}
83
12cc7127cb73
twoway (function `tcc', range(-4 4)), /// 
84
12cc7127cb73
	xtitle("Theta") ytitle("Percent Correct") title("Test Characteristic Curve")
85
12cc7127cb73
86
12cc7127cb73
** DEMO 4: Estimating IRT models using OpenIRT
87
12cc7127cb73
88
3e5f3f33ee42
* load response data
89
12cc7127cb73
sysuse naep_children, clear
90
3e5f3f33ee42
91
3e5f3f33ee42
* Preliminary exploration: percent correct score
92
3e5f3f33ee42
egen percent_correct = rowmean(item*)
93
3e5f3f33ee42
kdensity percent_correct, xtitle("Percent Correct") title(NAEP Percent Correct Score Distribution)
94
3e5f3f33ee42
95
3e5f3f33ee42
* Often useful to check that items are positive correlated 
96
3e5f3f33ee42
* with percent correct score
97
3e5f3f33ee42
corr percent_correct item*
98
3e5f3f33ee42
99
12cc7127cb73
* Read help...
100
12cc7127cb73
help openirt
101
12cc7127cb73
102
12cc7127cb73
* Example 1: Estimate both item parameters and ability for single test
103
bf363d47e970
openirt, id(id) item_prefix(item) save_item_parameters("items.dta") save_trait_parameters("traits.dta")
104
bf363d47e970
105
3e5f3f33ee42
* Merge in ability estimates
106
3e5f3f33ee42
merge id using traits, sort
107
3e5f3f33ee42
108
3e5f3f33ee42
* Compare distributions using different estimates
109
3e5f3f33ee42
	
110
3e5f3f33ee42
* Multiple plausible values can be combined to form better
111
3e5f3f33ee42
* kdensity estimate.  Using one plausible value works better though too.
112
3e5f3f33ee42
kdensity(theta_pv1), bw(.4) gen(x1 d1)
113
3e5f3f33ee42
kdensity(theta_pv2), bw(.4) gen(x2 d2) at(x1)
114
3e5f3f33ee42
kdensity(theta_pv3), bw(.4) gen(x3 d3) at(x1)
115
3e5f3f33ee42
kdensity(theta_pv4), bw(.4) gen(x4 d4) at(x1)
116
3e5f3f33ee42
kdensity(theta_pv5), bw(.4) gen(x5 d5) at(x1)
117
3e5f3f33ee42
egen d = rowmean(d*)
118
3e5f3f33ee42
line(d x1)
119
3e5f3f33ee42
120
3e5f3f33ee42
twoway (kdensity theta, bw(.4)) (kdensity theta_eap, bw(.4)) ///
121
3e5f3f33ee42
	(line d x1) (kdensity theta_mle, bw(.4)), ///
122
3e5f3f33ee42
	xtitle("Theta") title("True Theta vs EAP, PV, MLE Estimates") ///
123
3e5f3f33ee42
	legend(order(1 "True" 2 "EAP" 3 "PV" 4 "MLE"))
124
3e5f3f33ee42
125
3e5f3f33ee42
drop x* d*
126
3e5f3f33ee42
127
3e5f3f33ee42
* QQ plot distribution comparisons
128
3e5f3f33ee42
qqplot(theta_eap theta), xtitle("Theta (True)") ytitle("Theta (EAP)") title("") saving(tmp1.gph, replace)
129
3e5f3f33ee42
qqplot(theta_mle theta), xtitle("Theta (True)") ytitle("Theta (MLE)") title("") saving(tmp2.gph, replace)
130
3e5f3f33ee42
qqplot(theta_pv1 theta), xtitle("Theta (True)") ytitle("Theta (PV1)") title("") saving(tmp3.gph, replace)
131
3e5f3f33ee42
qqplot(theta_pv2 theta), xtitle("Theta (True)") ytitle("Theta (PV2)") title("") saving(tmp4.gph, replace)
132
3e5f3f33ee42
graph combine tmp1.gph tmp2.gph tmp3.gph tmp4.gph
133
3e5f3f33ee42
134
3e5f3f33ee42
* Graph TRUE vs EAP
135
3e5f3f33ee42
twoway (scatter theta_eap theta) (function y=x, range(-3 3)), ///
136
3e5f3f33ee42
	xtitle("Theta (True)") ytitle("Theta (EAP)") title("") ///
137
3e5f3f33ee42
  text(3 3 "y = x", place(e)) legend(off)
138
3e5f3f33ee42
139
3e5f3f33ee42
* Graph TRUE vs MLE
140
3e5f3f33ee42
twoway (scatter theta_mle theta) (function y=x, range(-3 3)), ///
141
3e5f3f33ee42
	xtitle("Theta (True)") ytitle("Theta (MLE)") title("") ///
142
3e5f3f33ee42
  text(3 3 "y = x", place(e)) legend(off)
143
3e5f3f33ee42
144
3e5f3f33ee42
* Item comparisons 
145
3e5f3f33ee42
* Load true parameters, for reference.
146
3e5f3f33ee42
sysuse naep_items, clear
147
3e5f3f33ee42
merge id using items, sort
148
3e5f3f33ee42
149
3e5f3f33ee42
twoway (scatter a_eap a) (function y = x, range(0 1.5)), xtitle(Discrimination (True)) ytitle(Discrimination (EAP))  ///
150
3e5f3f33ee42
	xscale(range(0 1.5)) ///
151
3e5f3f33ee42
	yscale(range(1 1.5))
152
3e5f3f33ee42
	
153
3e5f3f33ee42
twoway (scatter b_eap b) (function y = x, range(-2 2)), xtitle(Difficulty (True)) ytitle(Difficulty (EAP))  ///
154
3e5f3f33ee42
	xscale(range(-2 2)) ///
155
3e5f3f33ee42
	yscale(range(-2 2))
156
3e5f3f33ee42
	
157
3e5f3f33ee42
twoway (scatter c_eap c) (function y = x, range(0 .6)), xtitle(Guessing (True)) ytitle(Guessing (EAP))  ///
158
3e5f3f33ee42
	xscale(range(0 .6)) ///
159
3e5f3f33ee42
	yscale(range(0 .6))
160
3e5f3f33ee42
	
161
12cc7127cb73
* Example 2: Link two test forms
162
12cc7127cb73
sysuse naep_children, clear
163
12cc7127cb73
recode item1-item6 (0/1=.) if _n <= 250
164
12cc7127cb73
recode item7-item13 (0/1=.) if _n >250
165
12cc7127cb73
166
12cc7127cb73
openirt, id(id) item_prefix(item) save_item_parameters("items.dta") save_trait_parameters("traits.dta")
167
12cc7127cb73
168
12cc7127cb73
* Merge in ability estimates
169
12cc7127cb73
merge id using traits, sort
170
12cc7127cb73
171
12cc7127cb73
* Graph TRUE vs EAP
172
12cc7127cb73
twoway (scatter theta_eap theta) (function y=x, range(-3 3)), ///
173
12cc7127cb73
	xtitle("Theta (True)") ytitle("Theta (EAP)") title("") ///
174
12cc7127cb73
  text(3 3 "y = x", place(e)) legend(off)
175
12cc7127cb73
176
12cc7127cb73
* Graph TRUE vs MLE
177
12cc7127cb73
twoway (scatter theta_mle theta) (function y=x, range(-3 3)), ///
178
12cc7127cb73
	xtitle("Theta (True)") ytitle("Theta (MLE)") title("") ///
179
12cc7127cb73
  text(3 3 "y = x", place(e)) legend(off)
180
12cc7127cb73
181
12cc7127cb73
* Example 3: Fixed item parameters
182
12cc7127cb73
sysuse naep_items, clear
183
12cc7127cb73
save fixed_items, replace
184
12cc7127cb73
185
12cc7127cb73
sysuse naep_children, clear
186
12cc7127cb73
openirt, id(id) save_item_parameters("items.dta") save_trait_parameters("traits.dta") ///
187
12cc7127cb73
	fixed_item_file("fixed_items.dta") item_prefix(item)
188
12cc7127cb73
189
12cc7127cb73
* Merge in ability estimates
190
12cc7127cb73
merge id using traits, sort
191
12cc7127cb73
192
12cc7127cb73
* Graph TRUE vs EAP
193
12cc7127cb73
twoway (scatter theta_eap theta) (function y=x, range(-3 3)), ///
194
12cc7127cb73
	xtitle("Theta (True)") ytitle("Theta (EAP)") title("") ///
195
12cc7127cb73
  text(3 3 "y = x", place(e)) legend(off)
196
12cc7127cb73
197
12cc7127cb73
* Graph TRUE vs MLE
198
12cc7127cb73
twoway (scatter theta_mle theta) (function y=x, range(-3 3)), ///
199
12cc7127cb73
	xtitle("Theta (True)") ytitle("Theta (MLE)") title("") ///
200
12cc7127cb73
  text(3 3 "y = x", place(e)) legend(off)