Nothing
#' Attribute Profiles
#'
#' Given a number of attributes, it generates all possible attribute profiles (response patterns of latent variables)
#' @param nattributes a numeric value for number of attributes
#' @param attribute.names optional character vector of attribute names
#' @param profile.names optional character vector of attribute profile names
#' @return a matrix of dimension \code{2^nattributes X nattributes} containing binary values
#' @author Margi Dubal \email{margidubal@@gmail.com} & Diane Losardo \email{dlosardo@@amplify.com}
#' @usage GetAttributeProfiles(nattributes, attribute.names = NULL, profile.names = NULL)
#' @export
#' @examples
#'
#' \dontrun{
#'
#' GetAttributeProfiles(nattributes=3)
#' }
#'
GetAttributeProfiles <- function(nattributes, attribute.names = NULL, profile.names = NULL){
nclasses <- 2^nattributes
numeric.to.binary <- as.numeric(unlist(strsplit(as.character(binary(0:(nclasses-1))), "")))
pmatrix <- matrix(numeric.to.binary, nclasses, nattributes, byrow = T, dimnames = list(profile.names, attribute.names))
pmatrix
}
#' Parameter Names for All DCM Models
#'
#' Given a Q-matrix and parameterization method it generates item and structural parameter names. These are non-kernel parameters:
#' item thresholds (\code{taus}) and latent variable thresholds (\code{nus})
#' @param qmatrix a matrix of size (nitems X nattributes) that specifies which items are required for mastery of each attribute (i.e., latent variable)
#' @param nattributes a numeric value of number of attriutes
#' @param parameterization.method optional character string of parameterization method used to calibrated parameters.
#' If not specified then the default will be set to \code{Mplus}
#' @return a string vector of threshold parameter names
#' @author Margi Dubal \email{margidubal@@gmail.com} & Diane Losardo \email{dlosardo@@amplify.com}
#' @usage GetParameterNames(qmatrix, nattributes, parameterization.method = 'Mplus')
#' @export
#' @examples
#'
#' \dontrun{
#'
#' GetParameterNames(qmatrix = qmatrix.test, nattributes=3)
#' }
GetParameterNames <- function(qmatrix, nattributes, parameterization.method = 'Mplus'){
pmatrix <- GetAttributeProfiles(nattributes)
threshold.out <- NULL
for (c in 1:nrow(pmatrix)){
for (i in 1:nrow(qmatrix)){
# numeric vector of required attributes for an item i given qmatrix and class c
required.attributes <- which(qmatrix[i,] == 1)[which(qmatrix[i,] == 1) %in% which(pmatrix[c,] == 1)]
if (length(required.attributes) == 0) required.attributes = "0"
kernel <- paste(required.attributes, collapse = "")
threshold.out <- c(threshold.out, sprintf("tau%d_%s", i, kernel))
}
}
if(parameterization.method == "Mplus")
mus.out <- sprintf("mu_%d", 1:(nrow(pmatrix) - 1))
else
mus.out <- sprintf("mu_%d", 1:(nrow(pmatrix)))
return(c(unique(threshold.out), unique(mus.out)))
}
#' Obtain name of a particular lambda parameter
#'
#' Gets the name of a particular lambda parameter and produces a string of the
#' form: l_item_effect_attribtues.
#' @param item a numeric value representing item number
#' @param attributes a String of the attributes associated with this gamma
#' @return a String of the form: l_item_effect_attribtues.
GetLambdaName <- function(item, attributes){
return(sprintf("l%d_%d_%s", item, nchar(attributes), paste(attributes, collapse = "")))
}
#' Gets lambda names for a given item
#'
#' @param item.index.intercept a numeric value representing item number for the intercept lambda
#' @param item.index.main.effect a numeric value representing item number for the main effects lambda
#' @param required.attributes a numeric vector of attributes required to have mastered to get item correct
#' @return a String vector of lambda names for one item
GetLambdaNamesForItem <- function(item.index.intercept, item.index.main.effect, required.attributes){
final.lambdas <- sprintf("l%d_0", item.index.intercept)
if (any(grepl("&", required.attributes))){
required.attributes <- as.numeric(regmatches(required.attributes, regexpr('[0-9]+', required.attributes)))
for (i in 1:length(required.attributes)){
attrs <- combn(required.attributes, i, function(x) paste(x, collapse=""))
tmp.lambda <- sapply(attrs, function(x) GetLambdaName(item.index.main.effect, x))
final.lambdas <- c(final.lambdas, tmp.lambda)
}
} else if(any(grepl("\\|", required.attributes))){
required.attributes <- as.numeric(regmatches(required.attributes, regexpr('[0-9]+', required.attributes)))
tmp.lambda <- sapply(required.attributes, function(x) GetLambdaName(item.index.main.effect, x))
final.lambdas <- c(final.lambdas, tmp.lambda)
} else if(length(required.attributes) == 1) {
final.lambdas <- c(final.lambdas, sprintf("l%d_1_%s", item.index.main.effect, required.attributes))
}
return(final.lambdas)
}
#' Gets names of lambda parameters
#'
#' @param item.indexes.intercepts a numeric vector indicating which item is assoicated with the lamdba intercept
#' at the given index and thus allowing for equality constraints. For example, with nitems = 3,
#' this is c(1, 1, 1), that implies that intercept lambdas across items should be contrained to equality.
#' @param item.indexes.main.effects a numeric vector indicating which item is assoicated with the lamdba main effect
#' at the given index and thus allowing for equality constraints. For example, with nitems = 3,
#' this is c(1, 1, 1), that implies that main effect (and higher order) lambdas
#' across items should be contrained to equality.
#' @param required.attributes.lambda a nclasses by nitems matrix with each cell containing a String
#' representing the attributes required for the given class and item specific to lambda parameters.
#' @return a String vector of names of lambda parameters
GetLambdaNames <- function(item.indexes.intercepts, item.indexes.main.effects, required.attributes.lambda){
nitems <- ncol(required.attributes.lambda)
nclasses <- nrow(required.attributes.lambda)
all.lambdas <- NULL
lambda.equations <- matrix(NA, nclasses, nitems)
for (i in 1:ncol(required.attributes.lambda)){
lambdas <- NULL
for (c in 1:nrow(required.attributes.lambda)){
# numeric vector of required attributes for an item i given qmatrix and class c
required.attributes <- unlist(strsplit(required.attributes.lambda[c, i], ""))
cur.lambdas <- GetLambdaNamesForItem(item.indexes.intercepts[i]
, item.indexes.main.effects[i]
, required.attributes)
lambdas <- c(lambdas, cur.lambdas)
lambda.equations[c, i] <- paste(cur.lambdas, collapse = " + ")
}
all.lambdas <- c(all.lambdas, lambdas)
}
return(list(lambda.names = unique(all.lambdas), lambda.equations = lambda.equations))
}
#' Generate required attributes
#'
#' Generates a matrix of required attributes
#' @param qmatrix a nitems by nattributes matrix that specifies which items are required for mastery of each attribute (i.e., latent variable)
#' @param pmatrix a numeric nclasses by nattributes matrix of all possible attribute profiles
#' @return a nclasses by nitems character matrix with Strings representing the required attributes for a given item and class.
GetRequiredAttributes <- function(qmatrix, pmatrix){
apply(qmatrix, 1, function(y) {
aaply(pmatrix, 1, function(x)
paste(which(y ==1)[which(y== 1) %in% which(x== 1)], collapse = ""))}
)
}
#' Calculate required attributes for lamdbas fully specified DCM
#'
#' Calculates required attributes for a model parameterized in the LCDM framework using the fully
#' specified DCM model.
#' @param required.attributes.tau a nclasses by nitems matrix with each cell containing a String
#' representing the attributes required for the given class and item specific to tau parameters.
#' @return a nclasses by nitems matrix with each cell containing a String representing the
#' attributes required for the given class and item specific to lambda parameters for the a fully
#' specific DCM model.
GetRequiredAttributesLambdaFullDCM <- function(required.attributes.tau){
apply(required.attributes.tau, c(1,2), function(x) ifelse(nchar(x) > 1, paste(unlist(strsplit(x, "")), collapse="&"), x))
}
#' Calculate required attributes for lambdas for a DINA model.
#'
#' Calculates required attributes for a model parameterized in the LCDM framework using the DINA
#' model
#' @param required.attributes.tau a nclasses by nitems matrix with each cell containing a String
#' representing the attributes required for the given class and item specific to tau parameters.
#' @return a nclasses by nitems matrix with each cell containing a String representing the
#' attributes required for the given class and item specific to lambda parameters for the DINA model.
GetRequiredAttributesLambdaDina <- function(required.attributes.tau){
apply(required.attributes.tau, 2, function(x) ifelse(nchar(x) == max(nchar(x)), "e", ""))
}
#' Calculate required attributes for lambdas for a DINO model.
#'
#' Calculates required attributes for a model parameterized in the LCDM framework using the DINO
#' model
#' @param required.attributes.tau a nclasses by nitems matrix with each cell containing a String
#' representing the attributes required for the given class and item specific to tau parameters.
#' @return a nclasses by nitems matrix with each cell containing a String representing the
#' attributes required for the given class and item specific to lambda parameters for the DINO model.
GetRequiredAttributesLambdaDino <- function(required.attributes.tau){
apply(required.attributes.tau, 2, function(x) ifelse(x == "", "", "e"))
}
#' Calculate required attributes for lambdas for a CRUM model.
#'
#' Calculates required attributes for a model parameterized in the LCDM framework using the CRUM
#' model
#' @param required.attributes.tau a nclasses by nitems matrix with each cell containing a String
#' representing the attributes required for the given class and item specific to tau parameters.
#' @return a nclasses by nitems matrix with each cell containing a String representing the
#' attributes required for the given class and item specific to lambda parameters for the CRUM model.
GetRequiredAttributesLambdaCrum <- function(required.attributes.tau){
apply(required.attributes.tau, c(1,2), function(x) ifelse(nchar(x) > 1, paste(unlist(strsplit(x, "")), collapse="|"), x))
}
#' Calculate required attributes for lambdas for a NIDO model.
#'
#' Calculates required attributes for a model parameterized in the LCDM framework using the NIDO
#' model
#' @param required.attributes.tau a nclasses by nitems matrix with each cell containing a String
#' representing the attributes required for the given class and item specific to tau parameters.
#' @return a nclasses by nitems matrix with each cell containing a String representing the
#' attributes required for the given class and item specific to lambda parameters for the NIDO model.
GetRequiredAttributesLambdaNido <- function(required.attributes.tau){
apply(required.attributes.tau, c(1,2), function(x) ifelse(nchar(x) > 1, paste(unlist(strsplit(x, "")), collapse="|"), x))
}
#' Obtain name of a particular gamma parameter
#'
#' Produces a string of the form: g_effect_attribtues representing gamma parameters
#' @param attributes a string of the attributes associated with this gamma parameter
#' @return a string of the form g_effect_attribtues.
GetGammaName <- function(attributes){
return(sprintf("g_%d_%s", nchar(attributes), paste(strsplit(attributes, "")[[1]], collapse = "")))
}
#' Obtain names of all gamma parameters
#'
#' Gets names of all gamma parameters
#' @param required.attributes a numeric vector of attributes required to have mastered to get item correct
#' @return a String vector of names for gamma parameters
GetGammaNames <- function(required.attributes){
final.gammas <- NULL
if (length(required.attributes) > 1){
for (i in 1:length(required.attributes)){
attrs <- combn(required.attributes, i, function(x) paste(x, collapse=""))
tmp.gamma <- sapply(attrs, function(x) GetGammaName(x))
final.gammas <- c(final.gammas, tmp.gamma)
}
}
if (length(required.attributes) == 1) {
final.gammas <- c(final.gammas, sprintf("g_1_%d", required.attributes))
}
return(unique(final.gammas))
}
#' Kernel Parameter Names for all DCM Models
#' Given a Q-matrix and model type it generates item and structural parameter names. These are kernel parameters:
#' item thresholds (\code{lambdas}) and latent variable thresholds (\code{gammas})
#' @param qmatrix a matrix of size (nitems X nattributes) that specifies which items are required for mastery of each attribute (i.e., latent variable)
#' @param nattributes a numeric value of number of attriutes
#' @param model.type a string value of \code{DCM}, \code{DINA}, \code{CRUM}, \code{DINO},
#' \code{NIDO}, \code{NCRUM}.
#' If not specified then the default will be set to \code{DCM}
#' @return a string vector of threshold parameter names
#' @author Margi Dubal \email{margidubal@@gmail.com} & Diane Losardo \email{dlosardo@@amplify.com}
#' @usage GetKernelParameterNames(qmatrix, nattributes, model.type = "DCM")
#' @export
#' @examples
#'
#' \dontrun{
#'
#' GetKernelParameterNames(qmatrix = qmatrix.test, nattributes=3)
#' }
#'
GetKernelParameterNames <- function(qmatrix, nattributes, model.type = "DCM"){
pmatrix <- GetAttributeProfiles(nattributes)
nitems <- nrow(qmatrix)
nclasses <- nrow(pmatrix)
gamma.names <- GetGammaNames(which(pmatrix[nclasses,] == 1))
required.attributes.tau <- GetRequiredAttributes(qmatrix, pmatrix)
if (model.type == "DCM"){
required.attributes.lambda <- GetRequiredAttributesLambdaFullDCM(required.attributes.tau)
item.indexes.intercepts <- c(1:nitems)
item.indexes.main.effects <- c(1:nitems)
}
if (model.type == "DINA"){
required.attributes.lambda <- GetRequiredAttributesLambdaDina(required.attributes.tau)
item.indexes.intercepts <- c(1:nitems)
item.indexes.main.effects <- c(1:nitems)
}
if (model.type == "DINO"){
required.attributes.lambda <- GetRequiredAttributesLambdaDino(required.attributes.tau)
item.indexes.intercepts <- c(1:nitems)
item.indexes.main.effects <- c(1:nitems)
}
if (model.type == "CRUM"){
required.attributes.lambda <- GetRequiredAttributesLambdaCrum(required.attributes.tau)
item.indexes.intercepts <- c(1:nitems)
item.indexes.main.effects <- c(1:nitems)
}
if (model.type == "NIDO"){
required.attributes.lambda <- GetRequiredAttributesLambdaNido(required.attributes.tau)
item.indexes.intercepts <- c(1:nitems)
item.indexes.main.effects <- rep(1, nitems)
}
if (model.type == "NCRUM"){
pi.i.stars <- sprintf("pi.%d.star", 1:nrow(qmatrix))
r.ia.stars <- unlist(sapply(1:nrow(qmatrix), function(x) sprintf("r.%d.%d.star", x, which(qmatrix[x, ] == 1))))
return(list(pis.rias = c(pi.i.stars, r.ia.stars), gammas = gamma.names))
} else {
lambda.names.structure <- GetLambdaNames(item.indexes.intercepts
, item.indexes.main.effects
, required.attributes.lambda)
}
return(list(lambdas = lambda.names.structure, gammas = gamma.names))
}
#' Obtain item threshold labels
#'
#' Gets item threshold labels for a given qmatrix and pmatrix
#' @param qmatrix a numeric nitems by nattributes matrix that specifies which items are required for mastery of each attribute (i.e., latent variable)
#' @param pmatrix a numeric nclasses by nattributes matrix of all possible attribute profiles
#' @return an nclasses by nitems character matrix with appropriate threshold labels.
#' @export
GetThresholdLabels <- function(qmatrix, pmatrix){
threshold.labels <- NULL
for (i in 1:nrow(qmatrix)){
item.threshold.labels <- NULL
for (c in 1:nrow(pmatrix)){
# numeric vector of required attributes for an item i given qmatrix and class c
required.attributes <- which(qmatrix[i,] == 1)[which(qmatrix[i,] == 1) %in% which(pmatrix[c,] == 1)]
if (length(required.attributes) == 0) required.attributes = "0"
item.threshold.labels <- c(item.threshold.labels, sprintf("tau%d_%s", i, paste(required.attributes, collapse = "")))
}
threshold.labels <- cbind(threshold.labels, item.threshold.labels)
}
colnames(threshold.labels) <- sprintf("Item%d", 1:nrow(qmatrix))
return(threshold.labels)
}
#' Obtain attribute profile probabilities from latent variable means
#'
#' Gets all attribute profile probabilities given mu parameters (latent variable means)
#' @param mus a 1 by nclasses numeric vector of latent variable means
#' @return a numeric vector of all attribute profile probability values
GetClassProbsFromMus <- function(mus){
nu <- sapply(mus, function(x) exp(x)/(sum(exp(mus))))
names(nu) <- sprintf("nu_%d", 1:length(nu))
return(nu)
}
#' Calculate value for pi.i.star.prime for one item
#'
#' Given an NCRUM parameterization and values for pi.i.star, r.ia.star, and qmatrix, calculates the value for
#' for pi.i.star.prime for the given item
#' @param pi.i.star a numeric value for the probability that a person responds correctly given they have not mastered
#' any attributes before being penalized for not mastering an attribute.
#' @param r.ia.star a numeric 1 x nattributes vector of the penalty probabilities for this item of a correct response
#' for each required attribute that has not been mastered.
#' @param q.ia a numeric 1 x nattributes vector of the qmatrix entries for the given item.
#' @return a numeric value representing the pi.i.star_prime for item i
CalculatePiIStarPrime <- function(pi.i.star, r.ia.star, q.ia){
pi.i.star*prod(r.ia.star^(q.ia))
}
#' Calculate item probability of correct response for NCRUM parameterization
#'
#' Calculates the probability of a correct response for an item given an NCRUM parameterization
#' @param pi.i.star.prime a numeric value for the probability of a correct response for item i given
#' that no attributes have been mastered.
#' @param r.ia.star a numeric 1 x nattributes vector of the penalty probabilities for this item of a correct response
#' for each required attribute that has not been mastered.
#' @param q.ia a numeric 1 x nattributes vector of the qmatrix entries for the given item.
#' @param alphas a numeric 1 x nattributes vector with a 1 if a student has mastered an attribute and 0 otherwise.
#' @return the numeric value representing the probability of a correct response for the ith item.
GetProbCorrectNcrum <- function(pi.i.star.prime, r.ia.star, q.ia, alphas){
pi.i.star.prime*prod(1/r.ia.star^(q.ia*alphas))
}
#' Calculate all item probabilities of correct response for NCRUM parameterization
#'
#' Calculates the probabilities of a correct response for all items given an NCRUM parameterization
#' @param pi.i.star.prime a numeric 1 x nitems vector of the probabilities of a correct response for each item given
#' that no attributes have been mastered.
#' @param r.ia.star.qmatrix a numeric nitems x nattributes vector of the penalty probabilities for each item of
#' a correct response for each required attribute that has not been mastered.
#' @param qmatrix a numeric nitems by nattributes matrix that specifies which items are required for mastery of each attribute (i.e., latent variable)
#' @param alphas a numeric 1 x n_attributes vector with a 1 if a student has mastered an attribute and 0 otherwise.
#' @return probabilities of a correct response for all items given a person's attribute profile.
GetAllProbsCorrectNcrum <- function(pi.i.star.prime, r.ia.star.qmatrix, qmatrix, alphas){
sapply(1:nrow(qmatrix), function(x) GetProbCorrectNcrum(pi.i.star.prime[x], r.ia.star.qmatrix[x, ],
qmatrix[x, ], alphas))
}
#' Calculate item threshold values for NCRUM parameterization
#'
#' Calculates all item threshold values for an NCRUM parameterization given parameter estimates,
#' qmatrix, attribute profiles, and threshold label matrix.
#' @param estimates0 a numeric vector of parameter estimates in the form of pis and rs
#' @param qmatrix a numeric nitems by nattributes matrix that specifies which items are required for mastery of each attribute (i.e., latent variable)
#' @param pmatrix a numeric nclasses by nattributes matrix of all possible attribute profiles
#' @param threshold.labels an nclasses by nitems character matrix with appropriate item threshold labels
#' @return a numeric vector of item threshold values
GetThresholdValuesKernelPiR <- function(estimates0, qmatrix, pmatrix, threshold.labels){
pi.i.stars <- unlist(estimates0[grep('^pi', names(estimates0))])
r.ia.stars <- unlist(estimates0[grep('^r', names(estimates0))])
r.ia.star.qmatrix <- t(qmatrix)
r.ia.star.qmatrix[r.ia.star.qmatrix==1] <- r.ia.stars
r.ia.star.qmatrix <- t(r.ia.star.qmatrix)
pi.i.star.primes <- sapply(1:nrow(qmatrix), function(x) CalculatePiIStarPrime(pi.i.stars[x], r.ia.star.qmatrix[x, ], qmatrix[x, ]))
probs <- t(apply(pmatrix, 1, function(x) GetAllProbsCorrectNcrum(pi.i.star.primes, r.ia.star.qmatrix, qmatrix, x)))
taus <- Logit(probs)
taus <- unique(as.vector(t(taus)))
names(taus) <- unique(as.vector(t(threshold.labels)))
return(taus)
}
#' Calculate item threshold values for kernel parameterization
#'
#' Calculates the item threshold values for a kernel parameterization of a DCM model using lambdas
#' @param lambda.equations an nclasses by nitems character matrix with tau values
#' represented as a function of lambda values
#' @param estimates0 a numeric vector of parameter estimates in the form of lambdas and gammas
#' @param threshold.labels an nclasses by nitems character matrix with appropriate threshold labels.
#' @return a list of a numeric vector of item threshold values and an nclasses by nitems numeric matrix
#' of item threshold values
GetThresholdValuesKernel <- function(lambda.equations, estimates0, threshold.labels){
nitems <- ncol(lambda.equations)
nclasses <- nrow(lambda.equations)
lambda.values <- unlist(estimates0[grep('^l', names(estimates0))])
threshold.values <- matrix(0, nclasses, nitems)
for (l in 1:length(lambda.values)){
for (i in 1:nitems){
if (any(grepl(names(lambda.values)[l], lambda.equations[,i]))){
threshold.values[grep(names(lambda.values)[l], lambda.equations[,i]), i] <- threshold.values[grep(names(lambda.values)[l], lambda.equations[,i]), i] + lambda.values[l]
}
}
}
taus <- unique(as.vector(t(threshold.values)))
names(taus) <- unique(as.vector(t(threshold.labels)))
return(list(taus = taus, threshold.values = threshold.values))
}
#' Calcualte attribute means from gamma parameters
#'
#' Give gamma parameters and all attribute profiles, calculates the attribute means (i.e., mus)
#' @param estimates0 a numeric vector of parameter estimates in the form of lambdas and gammas
#' @param pmatrix a numeric nclasses by nattributes matrix of all possible attribute profiles
GetMusFromGammas <- function(estimates0, pmatrix){
gamma.values <- unlist(estimates0[grep('^g', names(estimates0))])
all.mus <- NULL
all.mus <- c(all.mus, -1*(sum(gamma.values)))
for (i in 2:(nrow(pmatrix) - 1)){
cur.mu <- all.mus[1] + sum(gamma.values[which(pmatrix[i, ] == 1)])
if (length(which(pmatrix[i, ] == 1)) > 1){
tmp <- which(pmatrix[i, ] == 1)
cur.mu <- cur.mu + gamma.values[grep(sprintf("g_%d_%s", length(tmp), paste(tmp, collapse="")), names(gamma.values))]
}
all.mus <- c(all.mus, cur.mu)
}
all.mus <- c(all.mus, 0)
names(all.mus) <- sprintf("mu%d", 1:length(all.mus))
return(all.mus)
}
#' GetThresholdValues
#'
#' @param threshold.labels an nclasses by nitems character matrix with appropriate threshold labels.
#' @param taus numeric vector of taus correctly named
#' threshold.labels.cls: String vector of names of thresholds for given class
GetThresholdValues <- function(threshold.labels, taus){
t(sapply(1:nrow(threshold.labels), function(x) GetClassThresholds(taus, threshold.labels[x,])))
}
# Obtains correct threshold values ordered by item.
# inputs: taus: numeric vector of taus correctly named
# threshold.labels.cls: String vector of names of thresholds for given class
# returns: A 1 by nitem vector of threshold values ordered by item.
GetClassThresholds <- function(taus, thresholds.labels.class){
class.thresholds <- taus[names(taus) %in% thresholds.labels.class]
class.thresholds[order(as.numeric(regmatches(names(class.thresholds)
, regexpr('[0-9]+', names(class.thresholds)))))]
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.