library(irt)
irt
package contains many useful functions commonly used in psychometrics.
Item parameters are defined within three main objects types:
Item
object contains all of the information about a test/survey item. It
is the building block of Testlet
and Itempool
objects. It mainly contains
item parameters and item’s psychometric model. But it can also contain many
other item attributes such as item content
, item_id
. User can also define
additional attributes, for example, key
, enemies
, word_count
,
seed_group
, etc.
Testlet
object is a set of Item
objects. It can also have it’s own
psychometric model. User can also define additional attributes.
Itempool
object is a collection of Item
and Testlet
objects.
Item
In order to create an Item
object, the psychometric model and item parameter
values is sufficient. Specifying an item_id
field is required if Item
will be
used within an Itempool
or Testlet
.
A three parameter logistic model item (3PL
) requires a
, b
and c
parameters to be specified:
item1 <- item(a = 1.2, b = -.8, c = .33, model = "3PL")
item1
#> A '3PL' item.
#> Model: 3PL (Three-Parameter Logistic Model)
#> Model Parameters:
#> a = 1.2
#> b = -0.8
#> c = 0.33
#> D = 1
#>
#> --------------------------
a
is the item discrimination, b
is the item difficulty and c
is the
pseudo-guessing parameter.
By default, the value of scaling constant D
is specified as 1
. But it can be
overridden:
item1 <- item(a = 1.2, b = -.8, c = .33, D = 1.7, model = "3PL")
item1
#> A '3PL' item.
#> Model: 3PL (Three-Parameter Logistic Model)
#> Model Parameters:
#> a = 1.2
#> b = -0.8
#> c = 0.33
#> D = 1.7
#>
#> --------------------------
item_id
and content
field can be specified as well:
item1 <- item(a = 1.2, b = -.8, c = .33, D = 1.7, model = "3PL",
item_id = "ITM384", content = "Quadratic Equations")
item1
#> A '3PL' item.
#> Item ID: ITM384
#> Model: 3PL (Three-Parameter Logistic Model)
#> Content: Quadratic Equations
#> Model Parameters:
#> a = 1.2
#> b = -0.8
#> c = 0.33
#> D = 1.7
#>
#> --------------------------
Additional fields can be added through misc
field:
item1 <- item(a = 1.2, b = -.8, c = .33, D = 1.7, model = "3PL",
item_id = "ITM384", content = "Quadratic Equations",
misc = list(key = "A",
enemies = c("ITM664", "ITM964"),
seed_year = 2020,
target_grade = "11")
)
item1
#> A '3PL' item.
#> Item ID: ITM384
#> Model: 3PL (Three-Parameter Logistic Model)
#> Content: Quadratic Equations
#> Model Parameters:
#> a = 1.2
#> b = -0.8
#> c = 0.33
#> D = 1.7
#>
#> Misc:
#> key: "A"
#> enemies: "ITM664", "ITM964"
#> seed_year: 2020
#> target_grade: "11"
#> --------------------------
An item characteristic curve can be plotted using plot
function:
plot(item1)
Rasch
model item requires b
parameter to be specified:
item2 <- item(b = -.8, model = "Rasch")
item2
#> A 'Rasch' item.
#> Model: Rasch (Rasch Model)
#> Model Parameters:
#> b = -0.8
#>
#> --------------------------
For Rasch
model, D
parameter cannot be specified.
1PL
ModelA one-parameter model item requires b
parameter to be specified:
item3 <- item(b = -.8, D = 1.7, model = "1PL")
item3
#> A '1PL' item.
#> Model: 1PL (One-Parameter Logistic Model)
#> Model Parameters:
#> b = -0.8
#> D = 1.7
#>
#> --------------------------
2PL
ModelA two-parameter model item requires a
and b
parameters to be specified:
item4 <- item(a = 1.2, b = -.8, D = 1.702, model = "2PL")
item4
#> A '2PL' item.
#> Model: 2PL (Two-Parameter Logistic Model)
#> Model Parameters:
#> a = 1.2
#> b = -0.8
#> D = 1.702
#>
#> --------------------------
4PL
ModelA four-parameter model item requires a
, b
, c
and d
parameters to be
specified:
item5 <- item(a = 1.06, b = 1.76, c = .13, d = .98, model = "4PL",
item_id = "itm-5")
item5
#> A '4PL' item.
#> Item ID: itm-5
#> Model: 4PL (Four-Parameter Logistic Model)
#> Model Parameters:
#> a = 1.06
#> b = 1.76
#> c = 0.13
#> d = 0.98
#> D = 1
#>
#> --------------------------
d
is the upper-asymptote parameter.
GRM
)A Graded Response model item requires a
and b
parameters to be specified.
b
parameters is ascending vector of threshold parameters:
item6 <- item(a = 1.22, b = c(-1.9, -0.37, 0.82, 1.68), model = "GRM",
item_id = "itm-6")
item6
#> A 'GRM' item.
#> Item ID: itm-6
#> Model: GRM (Graded Response Model)
#> Model Parameters:
#> a = 1.22
#> b = -1.9; -0.37; 0.82; 1.68
#> D = 1
#>
#> --------------------------
plot(item6)
D
parameter can also be specified.
GPCM
)A Generalized Partial Credit model item requires a
and b
parameters to be
specified. b
parameters is ascending vector of threshold parameters:
item7 <- item(a = 1.22, b = c(-1.9, -0.37, 0.82, 1.68), D = 1.7, model = "GPCM",
item_id = "itm-7")
item7
#> A 'GPCM' item.
#> Item ID: itm-7
#> Model: GPCM (Generalized Partial Credit Model)
#> Model Parameters:
#> a = 1.22
#> b = -1.9; -0.37; 0.82; 1.68
#> D = 1.7
#>
#> --------------------------
PCM
)A Partial Credit model item requires b
parameters to be
specified. b
parameters is ascending vector of threshold parameters:
item8 <- item(b = c(-1.9, -0.37, 0.82, 1.68), model = "PCM")
item8
#> A 'PCM' item.
#> Model: PCM (Partial Credit Model)
#> Model Parameters:
#> b = -1.9; -0.37; 0.82; 1.68
#>
#> --------------------------
An item with random item parameters can be generated using generate_item
function:
generate_item("3PL")
#> A '3PL' item.
#> Model: 3PL (Three-Parameter Logistic Model)
#> Model Parameters:
#> a = 0.4768
#> b = 0.5809
#> c = 0.0192
#> D = 1
#>
#> Misc:
#> key: "D"
#> possible_options: "A", "B", "C", "D"
#> --------------------------
generate_item("2PL")
#> A '2PL' item.
#> Model: 2PL (Two-Parameter Logistic Model)
#> Model Parameters:
#> a = 0.9363
#> b = -2.2367
#> D = 1
#>
#> Misc:
#> key: "D"
#> possible_options: "A", "B", "C", "D"
#> --------------------------
generate_item("Rasch")
#> A 'Rasch' item.
#> Model: Rasch (Rasch Model)
#> Model Parameters:
#> b = 1.0838
#>
#> Misc:
#> key: "C"
#> possible_options: "A", "B", "C", "D"
#> --------------------------
generate_item("GRM")
#> A 'GRM' item.
#> Model: GRM (Graded Response Model)
#> Model Parameters:
#> a = 1.5541
#> b = -2.1701; -0.5095; 0.3358
#> D = 1
#>
#> --------------------------
# The number of categories of polytomous items can be specified:
generate_item("GPCM", n_categories = 5)
#> A 'GPCM' item.
#> Model: GPCM (Generalized Partial Credit Model)
#> Model Parameters:
#> a = 1.1223
#> b = -0.2897; 0.5058; 0.8368; 1.5294
#> D = 1
#>
#> --------------------------
Testlet
A testlet is simply a collection of Item
objects:
item1 <- item(a = 1.2, b = -.8, c = .33, D = 1.7, model = "3PL",
item_id = "ITM384", content = "Quadratic Equations")
item2 <- item(a = 0.75, b = 1.8, c = .21, D = 1.7, model = "3PL",
item_id = "ITM722", content = "Quadratic Equations")
item3 <- item(a = 1.06, b = 1.76, c = .13, d = .98, model = "4PL",
item_id = "itm-5")
t1 <- testlet(c(item1, item2, item3))
t1
#> An object of class 'Testlet'.
#> Model: BTM
#>
#> Item List:
#>
#> item_id model a b c d D content
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
#> 1 ITM384 3PL 1.2 -0.8 0.33 NA 1.7 Quadratic Equations
#> 2 ITM722 3PL 0.75 1.8 0.21 NA 1.7 Quadratic Equations
#> 3 itm-5 4PL 1.06 1.76 0.13 0.98 1 <NA>
An testlet_id
field is required if testlet will be used in an item pool.
t1 <- testlet(item1, item2, item3, testlet_id = "T1")
t1
#> An object of class 'Testlet'.
#> Testlet ID: T1
#> Model: BTM
#>
#> Item List:
#>
#> item_id model a b c d D content
#> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
#> 1 ITM384 3PL 1.2 -0.8 0.33 NA 1.7 Quadratic Equations
#> 2 ITM722 3PL 0.75 1.8 0.21 NA 1.7 Quadratic Equations
#> 3 itm-5 4PL 1.06 1.76 0.13 0.98 1 <NA>
Itempool
An Itempool
object is the most frequently used object type in irt
package.
It is a collection of Item
and Testlet
objects.
item1 <- generate_item("3PL", item_id = "I1")
item2 <- generate_item("3PL", item_id = "I2")
item3 <- generate_item("3PL", item_id = "I3")
ip1 <- itempool(item1, item2, item3)
Item pools can be composed of items from different psychometric models and testlets:
item4 <- generate_item("GRM", item_id = "I4")
item5 <- generate_item("3PL", item_id = "T1-I1")
item6 <- generate_item("3PL", item_id = "T1-I2")
t1 <- testlet(item5, item6, item_id = "T1")
ip2 <- itempool(item1, item2, item3, item4, t1)
Most of the time item pools are generated using data frames:
n_item <- 6 # Number of items
ipdf <- data.frame(a = rlnorm(n_item), b = rnorm(n_item),
c = runif(n_item, 0, .3))
ip3 <- itempool(ipdf)
ip3
#> An object of class 'Itempool'.
#> Model of items: 3PL
#> D = 1
#>
#> item_id a b c
#> <chr> <dbl> <dbl> <dbl>
#> 1 Item_1 0.458 -1.15 0.289
#> 2 Item_2 0.742 0.193 0.0461
#> 3 Item_3 0.825 -0.737 0.0190
#> 4 Item_4 1.20 -0.692 0.0372
#> 5 Item_5 1.14 -0.333 0.231
#> 6 Item_6 16.3 1.06 0.187
# Scaling constant can be specified
ip4 <- itempool(ipdf, D = 1.7)
ip4
#> An object of class 'Itempool'.
#> Model of items: 3PL
#> D = 1.7
#>
#> item_id a b c
#> <chr> <dbl> <dbl> <dbl>
#> 1 Item_1 0.458 -1.15 0.289
#> 2 Item_2 0.742 0.193 0.0461
#> 3 Item_3 0.825 -0.737 0.0190
#> 4 Item_4 1.20 -0.692 0.0372
#> 5 Item_5 1.14 -0.333 0.231
#> 6 Item_6 16.3 1.06 0.187
ipdf <- data.frame(
item_id = c("Item_1", "Item_2", "Item_3", "Item_4", "Item_5", "Item_6"),
model = c("3PL", "3PL", "3PL", "GPCM", "GPCM", "GPCM"),
a = c(1.0253, 1.3609, 1.6617, 1.096, 0.9654, 1.3995),
b1 = c(NA, NA, NA, -1.112, -0.1709, -1.1324),
b2 = c(NA, NA, NA, -0.4972, 0.2778, -0.5242),
b3 = c(NA, NA, NA, -0.0077, 0.9684, NA),
D = c(1.7, 1.7, 1.7, 1.7, 1.7, 1.7),
b = c(0.7183, -0.4107, -1.5452, NA, NA, NA),
c = c(0.0871, 0.0751, 0.0589, NA, NA, NA),
content = c("Geometry", "Algebra", "Algebra", "Geometry", "Algebra",
"Algebra")
)
ip5 <- itempool(ipdf)
Itempool
objects can also be converted to a data frame:
as.data.frame(ip2)
#> item_id testlet_id model a b c b1 b2 b3 D key
#> 1 I1 <NA> 3PL 0.9027 -0.0463 0.1484 NA NA NA 1 C
#> 2 I2 <NA> 3PL 1.2123 0.7124 0.2154 NA NA NA 1 D
#> 3 I3 <NA> 3PL 1.0751 1.1153 0.2230 NA NA NA 1 D
#> 4 I4 <NA> GRM 1.1190 NA NA -1.5937 0.3181 1.3589 1 <NA>
#> 5 T1-I1 Testlet_1 3PL 1.2368 -0.5051 0.1002 NA NA NA 1 D
#> 6 T1-I2 Testlet_1 3PL 0.8357 0.8960 0.0016 NA NA NA 1 C
#> possible_options
#> 1 A, B, C, D
#> 2 A, B, C, D
#> 3 A, B, C, D
#> 4 NA
#> 5 A, B, C, D
#> 6 A, B, C, D
Probability of correct response (for dichotomous items) and probability of
each category (for polytomous items) can be calculated using prob
function:
item1 <- generate_item("3PL")
theta <- 0.84
# The probability of correct and incorrect response for `item1` at theta = 0.84
prob(item1, theta)
#> 0 1
#> [1,] 0.3103985 0.6896015
# Multiple theta values
prob(item1, theta = c(-1, 1))
#> 0 1
#> [1,] 0.7168617 0.2831383
#> [2,] 0.2783276 0.7216724
# Polytomous items:
item2 <- generate_item(model = "GPCM")
prob(item2, theta = 1)
#> 0 1 2 3
#> [1,] 0.0181105 0.1707979 0.5781817 0.2329099
prob(item2, theta = c(-1, 0, 1))
#> 0 1 2 3
#> [1,] 0.6553320 0.2958140 0.04792984 0.000924134
#> [2,] 0.2115960 0.4365783 0.32333048 0.028495280
#> [3,] 0.0181105 0.1707979 0.57818171 0.232909901
Probability of correct response (or category) for each item in an item pool can be calculated as:
ip <- generate_ip(model = "3PL", n = 7)
ip
#> An object of class 'Itempool'.
#> Model of items: 3PL
#> D = 1
#> possible_options = c("A", "B", "C", "D")
#>
#> item_id a b c key
#> <chr> <dbl> <dbl> <dbl> <chr>
#> 1 Item_1 0.716 0.217 0.253 D
#> 2 Item_2 0.874 0.861 0.214 A
#> 3 Item_3 1.86 0.974 0.231 C
#> 4 Item_4 0.840 -0.258 0.160 A
#> 5 Item_5 0.911 1.98 0.266 C
#> 6 Item_6 1.46 0.296 0.177 A
#> 7 Item_7 0.634 0.870 0.0836 B
prob(ip, theta = 0)
#> 0 1
#> Item_1 0.4024527 0.5975473
#> Item_2 0.5344001 0.4655999
#> Item_3 0.6608946 0.3391054
#> Item_4 0.3744612 0.6255388
#> Item_5 0.6299144 0.3700856
#> Item_6 0.4988078 0.5011922
#> Item_7 0.5815182 0.4184818
# When there are multiple theta values, a list where each element corresponds
# to a theta value returned.
prob(ip, theta = c(-2, 0, 1))
#> [[1]]
#> 0 1
#> Item_1 0.6201176 0.3798824
#> Item_2 0.7266214 0.2733786
#> Item_3 0.7662261 0.2337739
#> Item_4 0.6817440 0.3182560
#> Item_5 0.7147542 0.2852458
#> Item_6 0.7946347 0.2053653
#> Item_7 0.7886959 0.2113041
#>
#> [[2]]
#> 0 1
#> Item_1 0.4024527 0.5975473
#> Item_2 0.5344001 0.4655999
#> Item_3 0.6608946 0.3391054
#> Item_4 0.3744612 0.6255388
#> Item_5 0.6299144 0.3700856
#> Item_6 0.4988078 0.5011922
#> Item_7 0.5815182 0.4184818
#>
#> [[3]]
#> 0 1
#> Item_1 0.2714881 0.7285119
#> Item_2 0.3691917 0.6308083
#> Item_3 0.3754810 0.6245190
#> Item_4 0.2165827 0.7834173
#> Item_5 0.5203189 0.4796811
#> Item_6 0.2171664 0.7828336
#> Item_7 0.4393019 0.5606981
Item characteristic curves (ICC) can be plotted:
# Plot ICC of each item in the item pool
plot(ip)
# Plot test characteristic curve
plot(ip, type = "tcc")
Information value of an item at a given \(\theta\) value can also be calculated:
item1 <- generate_item("3PL")
info(item1, theta = -2)
#> [1] 0.02406235
# Multiple theta values
info(item1, theta = c(-1, 1))
#> [1] 0.04919700 0.08960753
# Polytomous items:
item2 <- generate_item(model = "GPCM")
info(item2, theta = 1)
#> [1] 0.5427016
info(item2, theta = c(-1, 0, 1))
#> [1] 0.8909455 1.1019585 0.5427016
Information values for each item in an item pool can be calculated as:
ip <- generate_ip(model = "3PL", n = 7)
ip
#> An object of class 'Itempool'.
#> Model of items: 3PL
#> D = 1
#> possible_options = c("A", "B", "C", "D")
#>
#> item_id a b c key
#> <chr> <dbl> <dbl> <dbl> <chr>
#> 1 Item_1 0.833 -0.951 0.0354 C
#> 2 Item_2 0.934 0.970 0.184 B
#> 3 Item_3 1.39 -0.112 0.288 A
#> 4 Item_4 1.43 0.257 0.218 C
#> 5 Item_5 1.02 -0.638 0.0673 B
#> 6 Item_6 1.11 -0.100 0.246 A
#> 7 Item_7 1.50 1.12 0.220 D
info(ip, theta = 0)
#> Item_1 Item_2 Item_3 Item_4 Item_5 Item_6 Item_7
#> [1,] 0.1413498 0.1001709 0.2730636 0.2959566 0.2114078 0.1887165 0.1056933
info(ip, theta = c(-2, 0, 1))
#> Item_1 Item_2 Item_3 Item_4 Item_5 Item_6
#> [1,] 0.12822222 0.00994675 0.01750681 0.008938492 0.1221402 0.02964977
#> [2,] 0.14134978 0.10017088 0.27306358 0.295956630 0.2114078 0.18871654
#> [3,] 0.09134627 0.15085687 0.18723309 0.285300661 0.1277243 0.15170483
#> Item_7
#> [1,] 0.000624366
#> [2,] 0.105693322
#> [3,] 0.346033174
Information functions can be plotted:
# Plot information function of each item
plot_info(ip)
# Plot test information function
plot_info(ip, tif = TRUE)
For a given set of item parameters and item responses, the ability ($\theta$)
estimates can be calculated using est_ability
function.
# Generate an item pool
ip <- generate_ip(model = "2PL", n = 10)
true_theta <- rnorm(5)
resp <- sim_resp(ip = ip, theta = true_theta, output = "matrix")
# Calculate raw scores
est_ability(resp = resp, ip = ip, method = "sum_score")
#> $est
#> S1 S2 S3 S4 S5
#> 4 3 3 5 7
#>
#> $se
#> S1 S2 S3 S4 S5
#> NA NA NA NA NA
# Estimate ability using maximum likelihood estimation:
est_ability(resp = resp, ip = ip, method = "ml")
#> $est
#> S1 S2 S3 S4 S5
#> -0.941935 -1.394198 -1.664643 -0.145236 0.732982
#>
#> $se
#> S1 S2 S3 S4 S5
#> 0.778740 0.776946 0.792755 0.816266 0.887546
# Estimate ability using EAP estimation:
est_ability(resp = resp, ip = ip, method = "eap")
#> $est
#> S1 S2 S3 S4 S5
#> -0.570637 -0.863875 -1.034963 -0.068463 0.442611
#>
#> $se
#> S1 S2 S3 S4 S5
#> 0.626353 0.623287 0.623245 0.637943 0.655944
# Estimate ability using EAP estimation with a different prior
# (prior mean = 0, prior standard deviation = 2):
est_ability(resp = resp, ip = ip, method = "eap", prior_pars = c(0, 2))
#> $est
#> S1 S2 S3 S4 S5
#> -0.804940 -1.226069 -1.479286 -0.086785 0.681779
#>
#> $se
#> S1 S2 S3 S4 S5
#> 0.747158 0.752559 0.764971 0.768755 0.822592