---
title: "Itempool Objects"
author: "Emre Gönülateş"
date: "`r Sys.Date()`"
output: 
  rmarkdown::html_vignette: 
    toc: true
vignette: >
  %\VignetteIndexEntry{Itempool Objects}
  %\VignetteEngine{knitr::knitr}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```
```{r setup}
library(irt)
```

An `Itempool` object is a collection of `Item` and `Testlet` objects. It
contains information of all items in a test or all items that will be used in an
item pool of an adaptive test.


## Creating an `Itempool` Object

### Dichotomous Items (`Rasch`, `1PL`, `2PL`, `3PL`, `4PL`)


There are multiple ways to create an `Itempool` object. If all of the items 
are from the same psychometric model, then using a `data.frame` object to create
an `Itempool` object is the most straightforward way. 


```{r}
# Create an item pool of 2PL items:
ip_dtf <- data.frame(
  a = c(1.1821, 0.6645, 0.8994, 1.0731, 1.0252, 1.2325, 0.9278, 1.0967), 
  b = c(0.4185, -0.5992, 0.2193, 0.8823, 0.4652, 1.4006, -1.1193, -0.3747))

ip <- itempool(ip_dtf, model = "2PL")
ip
```

If desired, `item_id`'s and content areas of each item can be specified:

```{r}
ip_dtf <- data.frame( 
  a = c(1.1821, 0.6645, 0.8994, 1.0731, 1.0252, 1.2325, 0.9278, 1.0967), 
  b = c(0.4185, -0.5992, 0.2193, 0.8823, 0.4652, 1.4006, -1.1193, -0.3747),
  item_id = c("i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8"), 
  content = c("Geometry", "Geometry", "Algebra", "Algebra", "Algebra", 
              "Geometry", "Algebra", "Algebra")
  )

ip <- itempool(ip_dtf, model = "2PL")
ip
```

By default, the scaling parameter `D` for most of the models are set to 1. 
This can be overwritten: 

```{r}
ip <- itempool(ip_dtf, model = "2PL", D = 1.7)
ip
```

Please review [psychometric models](irt-models.html) for other models and 
required parameters. For example, for `3PL` model: 

```{r}
ip_dtf <- data.frame(a = c(0.9303, 1.9423, 0.8417, 1.2622), 
                     b = c(1.3515, -0.5039, -1.7263, 1.3125), 
                     c = c(0.2301, 0.2224, 0.0967, 0.0112))
ip <- itempool(ip_dtf, model = "3PL", D = 1.7)
ip
```


### Polytomous Items (`GRM`, `GPCM`, `PCM`)

For polytomous items, usually a vector of item thresholds should be specified.
So, threshold (or step) parameters can given as the following example:

```{r}
ip_dtf <- data.frame(a = c(1.8619, 1.2458, 1.3213, 0.6174, 1.3625), 
                     b1 = c(-0.3666, -0.9717, -1.1588, 0.1093, 0.0858), 
                     b2 = c(0.3178, 0.2458, -0.4978, 0.6437, 0.5161), 
                     b3 = c(1.0384, 1.2382, 1.2787, 1.3609, 1.2145))

ip <- itempool(ip_dtf, model = "GPCM")
ip
```


The number of threshold parameters can be differ among items. In those cases, 
simply fill the rest of the values using `NA`:

```{r}
ip_dtf <- data.frame(a = c(1.175, 0.981, 1.0625, 0.9545, 0.7763), 
                     b1 = c(-0.9633, -0.4098, -0.298, 0.0576, -0.5342), 
                     b2 = c(-0.6213, NA, 0.4792, 0.538, 0.0363), 
                     b3 = c(0.5938, NA, NA, 0.9815, NA), 
                     b4 = c(NA, NA, NA, 1.3351, NA))
ip <- itempool(ip_dtf, model = "GRM", D = 1.702)
ip
```

An example reparameterized "GPCM" item pool (see 
[psychometric models](irt-models.html) vignette for details of this model):

```{r}
ip_dtf <- data.frame(a = c(1.1152, 0.8231, 0.9527, 0.6423), 
                     b = c(0.234, 0.0219,  0.7424, -0.3426), 
                     d1 = c(0.0081, 0.8569, -1.5181, -0.8458), 
                     d2 = c(0.3392, NA, -0.1978, 0.3756), 
                     d3 = c(NA, NA, 0.1677, NA))
ip <- itempool(ip_dtf, model = "GPCM2", D = 1.702)
ip
```



### Mixture of Models

If an `Itempool` object should consist of mixture of items, then the 
item parameter of each item should be specified as the examples above. But,
`model` should be specified for each item in the `data.frame`.

For example, the following item pool consists of three `3PL` items and two
`GPCM` items:


```{r}
ip_dtf <- data.frame(
  model = c("3PL", "3PL", "3PL", "GPCM", "GPCM"), 
  a = c(1.6242, 0.9471, 1.4643, 0.6582, 1.0234), 
  b = c(0.4563, -0.2994, -0.3027, NA, NA), 
  c = c(0.0156, 0.0339, 0.1243, NA, NA), 
  b1 = c(NA, NA, NA, -1.1532, -1.2171), 
  b2 = c(NA, NA, NA, -0.5384, -0.3992), 
  b3 = c(NA, NA, NA, 0.0591, 0.1431), 
  b4 = c(NA, NA, NA, NA, 1.52), 
  D = c(1.7, 1.7, 1.7, 1, 1))
ip <- itempool(ip_dtf)
ip
```


### Other Ways to Create `Itempool` Objects

An `Itempool` object can be created using individual `Item` and `Testlet` objects.
For example, in the the following code, individual `Item` objects are combined
to create an `Itempool` object. 

```{r}
ip <- c(item(model = "3PL", a = 2.09, b = 1.17, c = 0.25, item_id = "i1"), 
        item(model = "3PL", a = 0.59, b = 0.77, c = 0.13, item_id = "i2"), 
        item(model = "3PL", a = 1.67, b = 1.05, c = 0.04, item_id = "i3"), 
        item(model = "3PL", a = 0.84, b = -1.8, c = 0.24, item_id = "i4"), 
        item(model = "GPCM", a = 1.96, b = c(-0.94, -0.09, 0.25), item_id = "i5"), 
        item(model = "GPCM", a = 0.59, b = c(0.07, 1.46), item_id = "i6"), 
        item(model = "GPCM", a = 0.73, b = c(-1.2, -0.78, 0.2, 1.8), item_id = "i7"))
ip
```

Using this method, `Testlet` objects can be added to the item pool. 

```{r}
# Create a testlet object with three items. 
t1 <- testlet(c(item(model = "3PL", a = 2.09, b = 1.17, c = 0.25, item_id = "i1"), 
                item(model = "3PL", a = 0.59, b = 0.77, c = 0.13, item_id = "i2"), 
                item(model = "3PL", a = 1.67, b = 1.05, c = 0.04, item_id = "i3")), 
              testlet_id = "Testlet-932")
# Create another testlet object with two items. 
t2 <- testlet(c(item(model = "3PL", a = 0.84, b = -1.8, c = 0.24, item_id = "i4"), 
                item(model = "GPCM", a = 1.96, b = c(-0.94, -0.09, 0.25), 
                     item_id = "i5")), 
              testlet_id = "Testlet-77")
# Standalone items to be added:
i6 <- item(model = "GPCM", a = 0.59, b = c(0.07, 1.46), item_id = "i6")
i7 <- item(model = "GPCM", a = 0.73, b = c(-1.2, -0.78, 0.2, 1.8), item_id = "i7")

# Combine all items and testlets:
ip_testlet <- c(t1, t2, i6, i7)
ip_testlet
```


# Operations with `Itempool` Objects


We will show the operations that can be performed on an `Itempool` object 
using the following three example item pools:


```{r}
ip1 <- itempool(data.frame( 
  a = c(1.1821, 0.6645, 0.8994, 1.0731, 1.0252, 1.2325, 0.9278, 1.0967), 
  b = c(0.4185, -0.5992, 0.2193, 0.8823, 0.4652, 1.4006, -1.1193, -0.3747),
  item_id = c("i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8"), 
  content = c("Geometry", "Geometry", "Algebra", "Algebra", "Algebra", 
              "Geometry", "Algebra", "Algebra")
  ))
  
ip_mixed <- itempool(data.frame(
  model = c("3PL", "3PL", "3PL", "GPCM", "GPCM"), 
  a = c(1.6242, 0.9471, 1.4643, 0.6582, 1.0234), 
  b = c(0.4563, -0.2994, -0.3027, NA, NA), 
  c = c(0.0156, 0.0339, 0.1243, NA, NA), 
  b1 = c(NA, NA, NA, -1.1532, -1.2171), 
  b2 = c(NA, NA, NA, -0.5384, -0.3992), 
  b3 = c(NA, NA, NA, 0.0591, 0.1431), 
  b4 = c(NA, NA, NA, NA, 1.52), 
  D = c(1.7, 1.7, 1.7, 1.7, 1.7)))

ip_testlet <- c(
  testlet(c(item(model = "3PL", a = 2.09, b = 1.17, c = 0.25, item_id = "i1"), 
            item(model = "3PL", a = 0.59, b = 0.77, c = 0.13, item_id = "i2"), 
            item(model = "3PL", a = 1.67, b = 1.05, c = 0.04, item_id = "i3")), 
          testlet_id = "Testlet-932"), 
  item(model = "GPCM", a = 0.59, b = c(0.07, 1.46), item_id = "i6"),
  testlet(c(item(model = "3PL", a = 0.84, b = -1.8, c = 0.24, item_id = "i4"), 
            item(model = "GPCM", a = 1.96, b = c(-0.94, -0.09, 0.25), 
                 item_id = "i5")), 
          testlet_id = "Testlet-77"), 
  item(model = "GPCM", a = 0.73, b = c(-1.2, -0.78, 0.2, 1.8), item_id = "i7"))
```


## Combining Item Pools

Two `Itempool` objects can be combined using `c()` function. 

```{r}
ip <- c(ip1, ip_mixed)
ip
```

## Subsetting 

`Itempool` objects can be subsetted using brackets `[ ]`. This operation will 
always return an `Itempool` object. 

```{r}
# Subset only the first element of the item pool
ip1[1]

# Create an Itempool using the first and third element:
ip1[c(1, 3)] # Order is important
ip1[c(3, 1)]

# Create an Itempool using all but the second element: 
ip1[-2]

# Subsetting using item ID's:
ip1[c("i2", "i1")]

# Subsetting using logical operators:
ip1[ip1$b < 0]

# Select items with information values larger than 0.2 at theta = 1:
ip1[info(ip1, theta = 1) > 0.2]

```

## Extracting Items

An `Item` object can be extracted from an `Itempool` using double bracket 
operator `[[ ]]`. This operation will return an `Item` or `Testlet` object. 


```{r}
# Extract the second element
ip1[[2]]

# Extract a testlet
ip_testlet[[3]]
```

## Replacing Items of an `Itempool` 

Using the double bracket with assignment operator, individual items of an 
`Itempool` object can be replaced. 


```{r}
ip_new <- ip1
# Replace the second item with a new item
ip_new[[2]] <- item(a = 1, b = c(-1, 0, 1), model = "GRM", item_id = "NewItm4",
                    D = 1.7, content = "Quadratic Functions")
ip_new
```

## Accessing Parts of an `Itempool` object

`$` operator can be used to access parts of an `Itempool` object. Here, we will 
discuss the most common uses of this operator. The full list of available 
options can be found in the help page:

```{r, eval=FALSE}
?`$,Itempool-method`
```


```{r}
# Extract the ID's of the items within an item pool
ip1$item_id

# Extract the contents of the items within an item pool
ip1$content

# Extract the models of the items within an item pool
ip1$model
ip_mixed$model

# Maximum possible score of items
ip1$max_score
ip_mixed$max_score
ip_testlet$max_score

# Maximum scores of each standalone item
ip1$item_max_score
ip_mixed$item_max_score
ip_testlet$item_max_score


```

Item parameters can also be accessed:

```{r}
ip1$a
ip1$b
ip1$c
ip1$D

ip_mixed$a
ip_mixed$b
ip_mixed$b1
ip_mixed$b4
ip_mixed$D
```



Using the operator `$n`, we can extract a detailed summary of the number of 
`Item`s and `Testlet`s in the item pool. 
This is especially useful if the item pool has both standalone and testlet 
items. 

*  `$n$elements` gives the total number of testlets and standalone items. 
*  `$n$testlets` gives the total number of testlets. 
*  `$n$items` gives the total number of standalone items and items within 
    testlets. 

```{r}
# Extract the number of items within an item pool
ip1$n
# In ip_testlet, there are two testlets and two standalone items. Within those
# two testlets, there are a total of 5 items. At total there are 7 items.
ip_testlet$n
```


## Updating Parts of an `Itempool` object

Using `$<-` operator, the parts of an item pool can be updated. For example, 
using the following code, we can change the `item_id`s and `content`s of the items 
of an item pool. 

```{r}
ip_new <- ip1
ip_new$item_id <- paste0("Question-", 1:length(ip_new))
ip_new$content <- c("M", "M", "R", "M", "E", "R", "E", "M")

```

New item parameters can be set this way as well: 

```{r}
ip_new$a <- 1
ip_new
ip_new$b <- rnorm(length(ip_new))
ip_new
```






<!-- ## Converting an `Itempool` to a `data.frame`  -->


<!-- ## Converting an `Itempool` to a `list`  -->


<!-- ## Printing an `Itempool` -->



```{r, eval=FALSE, include=FALSE}

ip <- generate_ip(model = c("3PL", "3PL", "3PL", "3PL", "GPCM", "GPCM", "GPCM"))
dput(ip)
dput(as.data.frame(generate_ip(model = c("3PL", "3PL", "3PL", "3PL", "3PL"))))
dput(as.data.frame(generate_ip(model = "GPCM", n = 5)))
dput(as.data.frame(generate_ip(model = "GPCM2", n = 4, n_categories = c(3, 2, 4, 3))))
dput(as.data.frame(generate_ip(model = "GPCM", n = 5, n_categories = c(5, 2, 3, 4, 3))))

ip <- generate_ip(model = c("3PL", "3PL", "3PL", "GPCM", "GPCM"))
dput(data.frame(ip))
# list(key = c("A", "C", "D", "B", "B", "A", "D", "C"), 
#                            grade = c(11, 9, 9, 10, 10, 10, 11, 9))
```

