Skip to content

Commit ae103dc

Browse files
Merge pull request #4 from AnthonyRaborn/devel
Upgrade to v0.1.2
2 parents 811ed2b + 954e59b commit ae103dc

27 files changed

+1256
-463
lines changed

DESCRIPTION

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
Package: caMST
22
Type: Package
33
Title: Mixed Computerized Adaptive Multistage Testing
4-
Version: 0.1.0
5-
Date: 2018-08-22
4+
Version: 0.1.2
5+
Date: 2019-10-08
66
Authors@R: person("Anthony", "Raborn", email = "[email protected]", role = c("aut","cre"))
77
Description: Provides functions to more easily analyze computerized adaptive tests. Currently, functions for computerized
88
adaptive tests (CAT), computer adaptive multistage tests (CMT), and mixed computer adaptive multistage tests (McaMST)
@@ -13,10 +13,12 @@ Description: Provides functions to more easily analyze computerized adaptive tes
1313
License: LGPL (>= 2.0, < 3) | Mozilla Public License
1414
Encoding: UTF-8
1515
LazyData: true
16-
Depends: R (>= 3.2.3)
16+
Depends: R (>= 3.5.0)
1717
Imports: catR,
18-
mstR
18+
mstR,
19+
diagram,
20+
methods
1921
Suggests: testthat,
2022
knitr,
2123
rmarkdown
22-
RoxygenNote: 6.0.1
24+
RoxygenNote: 6.1.1

NAMESPACE

+7
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,10 @@
33
export(computerized_adaptive_test)
44
export(mixed_adaptive_test)
55
export(multistage_test)
6+
export(transition_matrix_plot)
7+
exportClasses(CAT)
8+
exportClasses(MAT)
9+
exportClasses(MST)
10+
import(utils)
11+
importFrom(methods,new)
12+
importFrom(stats,runif)

NEWS.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
# Package v0.1.0
1+
# Package v0.1.2
22
## Major Updates
3-
* Package first uploaded to github and CRAN.
4-
* Code style changed as compared to the inital iteration of the code.
5-
* Mixed computerized adaptive multistage testing (Mca-MST) seems to work for designs with an arbitrary number of MST stages (i.e., any number of post-routing stages).
6-
* Multistage testing (MST) seems to work for any arbitrary MST design AND includes an option for number correct (NC) scoring.
7-
* Computerized adaptive testing (CAT) seems to work; CAT function still needs to allow individuals to fine-tune the catR item selection function and stopping rules.
3+
- Each of the major functions now produce S4 objects with similar slots
4+
- This results in a more standardized and predictable set of outputs for each function
5+
- With the S4 classes, I've added a print method that summarizes the results of the functions
6+
- The `multistage_test` function can now perform two kinds of number correct scoring, instead of the original one, and records which scoring logic was used
7+
- A plot function was introduced to aid in creating publication-ready diagrams showing the multistage test design (including the mixed adaptive tests)
8+
- This function also works with the two relevant S4 objects created in this release

R/all_class_generics.R

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#' An S4 class for computerized adaptive tests
2+
#'
3+
#' @slot function.call The original function call.
4+
#' @slot final.theta.estimate Numeric vector of theta estimates calculated by the provided `method`.
5+
#' @slot eap.theta Numeric vector of theta estimates calculated by `catR::eapEst`.
6+
#' @slot final.theta.Baker Numeric vector of theta estimates calculated by the internal `iterative.theta.estimate` function.
7+
#' @slot final.theta.SEM Numeric vector of SEM estimates calculated by the internal `iterative.theta.estimate` function.
8+
#' @slot final.items.seen Character matrix of the final items seen by each individual.
9+
#' @slot final.responses Numeric matrix of the response patterns observed.
10+
#' @slot runtime A `difftime` object of the total run time of the function.
11+
#'
12+
#' @importFrom methods new
13+
#'
14+
#' @return An S4 object of class `CAT`.
15+
#' @export
16+
#'
17+
setClass('CAT',
18+
slots =
19+
list(
20+
function.call = 'call',
21+
final.theta.estimate = 'numeric',
22+
eap.theta = 'numeric',
23+
final.theta.Baker = 'numeric',
24+
final.theta.SEM = 'numeric',
25+
final.items.seen = 'matrix',
26+
final.responses = 'matrix',
27+
runtime = 'ANY'
28+
)
29+
)
30+
31+
setMethod('show',
32+
signature = 'CAT',
33+
definition = function(object) {
34+
Original.Call = object@function.call
35+
Total.Time = object@runtime
36+
Average.Theta = mean(object@final.theta.estimate)
37+
Average.SEM = mean(object@final.theta.SEM, na.rm = T)
38+
Average.Items = mean(apply(object@final.items.seen, 1, FUN = function(x) sum(!is.na(x))))
39+
40+
line0 = c("Test Format: Computerized Adaptive Test")
41+
line1 = Original.Call
42+
line2 = paste0("Total Run Time: ", round(Total.Time[[1]], 3), " ", attr(Total.Time, "units"))
43+
line3 = paste0("Average Theta Estimate: ", round(Average.Theta, 3))
44+
line4 = paste0("Average SEM: ", round(Average.SEM, 3))
45+
line5 = paste0("Average Number of Items Seen: ", round(Average.Items, 3))
46+
47+
cat(paste0(c(line0, line1, line2, line3, line4, line5), collapse = "\n"))
48+
})
49+
50+
#' An S4 method for multistage adaptive tests.
51+
#'
52+
#' @slot function.call The original function call.
53+
#' @slot final.theta.estimate Numeric vector of theta estimates calculated by the provided `method`.
54+
#' @slot eap.theta Numeric vector of theta estimates calculated by `catR::eapEst`.
55+
#' @slot final.theta.Baker Numeric vector of theta estimates calculated by the internal `iterative.theta.estimate` function.
56+
#' @slot final.theta.SEM Numeric vector of SEM estimates calculated by the internal `iterative.theta.estimate` function.
57+
#' @slot final.items.seen Character matrix of the final items seen by each individual.
58+
#' @slot modules.seen Numeric matrix of the modules seen by each individual.
59+
#' @slot final.responses Numeric matrix of the response patterns observed.
60+
#' @slot transition.matrix Numeric matrix; the transition matrix entered into the function.
61+
#' @slot n.stages Numeric; the number of stages specified.
62+
#' @slot nc.list A list of the number correct scoring logic and method, if applicable. Defaults to `NULL`.
63+
#' @slot runtime A `difftime` object of the total run time of the function.
64+
#'
65+
#' @importFrom methods new
66+
#'
67+
#' @return An S4 object of class `MST`.
68+
#' @export
69+
#'
70+
setClass('MST',
71+
slots =
72+
list(
73+
function.call = 'call',
74+
final.theta.estimate = 'numeric',
75+
eap.theta = 'numeric',
76+
final.theta.Baker = 'numeric',
77+
final.theta.SEM = 'numeric',
78+
final.items.seen = 'matrix',
79+
modules.seen = 'matrix',
80+
final.responses = 'matrix',
81+
transition.matrix = 'matrix',
82+
n.stages = 'numeric',
83+
nc.list = 'ANY',
84+
runtime = 'ANY'
85+
)
86+
)
87+
88+
setMethod('show',
89+
signature = 'MST',
90+
definition = function(object) {
91+
Original.Call = object@function.call
92+
Total.Time = object@runtime
93+
Average.Theta = mean(object@final.theta.estimate)
94+
Average.SEM = mean(object@final.theta.SEM, na.rm = T)
95+
Path.Taken = apply(object@modules.seen, 1, FUN = function(object) paste0(object, collapse = '-'))
96+
Most.Path = table(Path.Taken)[which(table(Path.Taken)==max(table(Path.Taken)))]
97+
98+
line0 = ifelse(
99+
test = is.null(object@nc.list),
100+
yes = c("Test Format: Multistage Adaptive Test"),
101+
no = ifelse(
102+
test = is.null(object@nc.list$method)|
103+
object@nc.list$method!="module_sum",
104+
yes = c("Test Format: Multistage Adaptive Test with Cumulative Summation Scoring"),
105+
no = c("Test Format: Multistage Adaptive Test with Module Summation Scoring")
106+
)
107+
)
108+
line1 = Original.Call
109+
line2 = paste0("Total Run Time: ", round(Total.Time[[1]], 3), " ", attr(Total.Time, "units"))
110+
line3 = paste0("Average Theta Estimate: ", round(Average.Theta, 3))
111+
line4 = paste0("Average SEM: ", round(Average.SEM, 3))
112+
line5 = paste0("Most Common Path(s) Taken: ", attr(Most.Path, 'names'), " taken by ", Most.Path, " subjects")
113+
114+
cat(paste0(c(line0, line1, line2, line3, line4, line5), collapse = "\n"))
115+
})
116+
117+
#' An S4 method for mixed adaptive tests.
118+
#'
119+
#' @slot function.call The original function call.
120+
#' @slot final.theta.estimate Numeric vector of theta estimates calculated by the provided `method`.
121+
#' @slot eap.theta Numeric vector of theta estimates calculated by `catR::eapEst`.
122+
#' @slot final.theta.Baker Numeric vector of theta estimates calculated by the internal `iterative.theta.estimate` function.
123+
#' @slot final.theta.SEM Numeric vector of SEM estimates calculated by the internal `iterative.theta.estimate` function.
124+
#' @slot final.items.seen Character matrix of the final items seen by each individual.
125+
#' @slot modules.seen Numeric matrix of the modules seen by each individual.
126+
#' @slot final.responses Numeric matrix of the response patterns observed.
127+
#' @slot transition.matrix Numeric matrix; the transition matrix entered into the function.
128+
#' @slot n.stages Numeric; the number of stages specified.
129+
#' @slot runtime A `difftime` object of the total run time of the function.
130+
#'
131+
#' @importFrom methods new
132+
#'
133+
#' @return An S4 object of class `MAT`.
134+
#' @export
135+
#'
136+
setClass('MAT',
137+
slots =
138+
list(
139+
function.call = 'call',
140+
final.theta.estimate = 'numeric',
141+
eap.theta = 'numeric',
142+
final.theta.Baker = 'numeric',
143+
final.theta.SEM = 'numeric',
144+
final.items.seen = 'matrix',
145+
modules.seen = 'matrix',
146+
final.responses = 'matrix',
147+
transition.matrix = 'matrix',
148+
n.stages = 'numeric',
149+
runtime = 'ANY'
150+
)
151+
)
152+
153+
setMethod('show',
154+
signature = 'MAT',
155+
definition = function(object) {
156+
Original.Call = object@function.call
157+
Total.Time = object@runtime
158+
Average.Theta = mean(object@final.theta.estimate)
159+
Average.SEM = mean(object@final.theta.SEM, na.rm = T)
160+
Path.Taken = apply(object@modules.seen, 1, FUN = function(object) paste0(object, collapse = '-'))
161+
Most.Path = table(Path.Taken)[which(table(Path.Taken)==max(table(Path.Taken)))]
162+
163+
line0 = c("Test Format: Mixed Adaptive Test")
164+
line1 = Original.Call
165+
line2 = paste0("Total Run Time: ", round(Total.Time[[1]], 3), " ", attr(Total.Time, "units"))
166+
line3 = paste0("Average Theta Estimate: ", round(Average.Theta, 3))
167+
line4 = paste0("Average SEM: ", round(Average.SEM, 3))
168+
line5 = paste0("Most Common Path(s) Taken: ", attr(Most.Path, 'names'), " taken by ", Most.Path, " subjects")
169+
170+
cat(paste0(c(line0, line1, line2, line3, line4, line5), collapse = "\n"))
171+
})
172+

R/caMST.R

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#' \code{caMST} package
2+
#'
3+
#' Computer Adaptive Mutistage Test Analysis
4+
#'
5+
#' See the README on \href{https://github.com/AnthonyRaborn/caMST#readme}{GitHub} for more information.
6+
#'
7+
#' @docType package
8+
#' @name caMST
9+
#' @importFrom stats runif
10+
NULL
11+
12+
13+
#' Create Package Startup Message
14+
#'
15+
#' Makes package startup message.
16+
#'
17+
#' Idea taken from https://github.com/ntguardian/MCHT/blob/master/R/StartupMessage.R
18+
#'
19+
#' @import utils
20+
#' @examples
21+
#' caMST:::caMSTStartup()
22+
23+
caMSTStartup <- function() {
24+
caMST <- c("
25+
___ ___ _____ _____
26+
| \\/ |/ ___||_ _|
27+
___ __ _ | . . |\\ `--. | |
28+
/ __| / _` || |\\/| | `--. \\ | |
29+
| (__ | (_| || | | |/\\__/ / | |
30+
\\___| \\__,_|\\_| |_/\\____/ \\_/
31+
")
32+
version <- paste("\tVersion", as.character(utils::packageVersion("caMST")))
33+
cat_penguin <- c("\t\\ /\\ \n\t ) ( ')\t >^)\n\t( / ) \t /\\\\ \n\t\\(__)|\t_\\_V")
34+
message <- c(caMST, version, cat_penguin)
35+
36+
cat(message, sep = "\n")
37+
}
38+
39+
#' Package Attach Hook Function
40+
#'
41+
#' Hook triggered when package attached.
42+
#'
43+
#' Idea taken from https://github.com/ntguardian/MCHT/blob/master/R/StartupMessage.R
44+
#'
45+
#' @param lib a character string giving the library directory where the package
46+
#' defining the namespace was found
47+
#' @param pkg a character string giving the name of the package
48+
#' @examples
49+
#' caMST:::.onAttach(.libPaths()[1], "caMST")
50+
51+
.onAttach <- function(lib, pkg) {
52+
msg <- caMSTStartup()
53+
if (!interactive())
54+
msg[1] <- paste("Package 'caMST' version", packageVersion("caMST"))
55+
packageStartupMessage(msg)
56+
invisible()
57+
}

R/computerized_adaptive_test_function.R

+24-14
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,18 @@
1010
#' @param nextItemControl A list of control values passed to \code{catR::nextItem}. See that function for more details.
1111
#' @param ... Further arguments to be passed to internal functions. Currently unimplemented.
1212
#'
13-
#' @return List of results.
14-
#' \item{final.theta.estimate.catR}{The final theta estimate as specified in the `method` argument}
15-
#' \item{eap.theta}{The expected a posteriori (EAP) theta estimate.}
16-
#' \item{final.theta.Baker}{The maximum likelihood estimate as described in chapter 5 of Baker (2001)[http://echo.edres.org:8080/irt/baker/final.pdf].}
17-
#' \item{final.theta.SEM}{The standard error of measurement of the `final.theta.estimate.catR`.}
18-
#' \item{final.items.seen}{The final items seen by each individual. A matrix of n rows and maxItems columns. NA indicates an individual wasn't administered any additional items after the last one specified in their row.}
19-
#' \item{final.responses}{The responses to the items in `final.items.seen`. A matrix of n rows and maxItems columns. NA indicates an individual wasn't administered any additional items after the last one specified in their row.}
13+
#' @return An S4 object of class 'CAT' with the following slots:
14+
#' \item{function.call}{The function and arguments called to create this object.}
15+
#' \item{final.theta.estimate}{A numeric vector of the final theta estimates using the \code{method} provided in \code{function.call}.}
16+
#' \item{eap.theta}{A numeric vector of the final theta estimates using the expected a posteriori (EAP) theta estimate from \code{catR::eapEst}.}
17+
#' \item{final.theta.Baker}{A numeric vector of the final theta estimates using an iterative maximum likelihood estimation procedure as described in chapter 5 of Baker (2001).}
18+
#' \item{final.theta.SEM}{A numeric vector of the final standard error of measurement (SEM) estimates using an iterative maximum likelihood estimation procedure as described in chapter 5 of Baker (2001)[http://echo.edres.org:8080/irt/baker/final.pdf].}
19+
#' \item{final.items.seen}{A matrix of the final items seen by each individual using the supplied item names. \code{NA} values indicate that an individual wasn't given any items to answer after the last specified item in their row.}
20+
#' \item{final.responses}{A matrix of the responses to the items seen in \code{final.items.seen}. \code{NA} values indicate that the individual didn't answer the question in the supplied response file or wasn't given any more items to answer.}
21+
#' \item{runtime}{A \code{difftime} object recording how long the function took to complete.}
2022
#' @export
23+
#' @references Baker, F. B. (2001). The basics of item response theory. For full text: http://echo.edres.org:8080/irt/baker/final.pdf.
24+
#' @seealso [mixed_adaptive_test] for a multistage test with a routing module using item-level adaptation.
2125
#'
2226
#' @examples
2327
#' data(example_thetas) # 5 simulated abilities
@@ -167,17 +171,23 @@ computerized_adaptive_test <-
167171
# end loop for this person; repeat loop for next
168172
}
169173

170-
# print total time this replication took to perform
171-
print(Sys.time() - start.time)
172-
173-
return(
174-
list(
175-
final.theta.estimate.catR = final.theta,
174+
# create results object
175+
results =
176+
new(
177+
'CAT',
178+
function.call = match.call(),
179+
final.theta.estimate = final.theta,
176180
eap.theta = final.theta.eap,
177181
final.theta.Baker = final.theta.Baker,
178182
final.theta.SEM = final.theta.SEM,
179183
final.items.seen = final.items.seen,
180-
final.responses = final.responses
184+
final.responses = final.responses,
185+
runtime = Sys.time() - start.time
181186
)
187+
188+
print(results@runtime)
189+
190+
return(
191+
results
182192
)
183193
}

0 commit comments

Comments
 (0)