# The Need for paste2 (part II)

April 29, 2012
By

(This article was first published on TRinker's R Blog » R, and kindly contributed to R-bloggers)

This is Part II of a multi part blog on the paste2 function…

In my first post on the paste2 function I promised a proof of a few practical uses.  The first example I have comes from psychometrics and comes out of a need left behind by ltm’s factor.score function.  You can fit a survey data set with an IRT model and the ltm package will allow you to figure out ability estimates for people achieving an exact combination of binary scores.  So for instance on a 6 question test a person may have the following score:

item1 item2 item3 item4 item5 item6
0     0     1     1     1     0

…meaning they got questions 1 and 2 wrong, 3-5 correct and question 6 incorrect.  A total score of 3.  Now the IRT model says that that particular combination has a particular ability estimate and a person with 3 different correct responses may not have the same ability score. The problem is factor.score gives the estimates but doesn’t tell you the ability scores for specific observations in the data set.

paste2 to the rescue!

Solution: Create a function, based on paste2, that pastes together all the observations’ scores as well as the estimates from the factor.scores function used after fitting a 1PL or 2PL model.  Now we have two character strings that look something like this: "001110"   Then we can easily use some  slick indexing and we have a basic look up table of ability scores to assign to each observation.  Here’s the script that does that:

########################
# THE ABILITY FUNCTION #
########################
ability <- function(dataset, items.index, fact.score, digits = 3, full = TRUE){
SD <- fact.score$score.dat nc <- ncol(SD) ncd <- ncol(dataset) IT <- SD[, -c((nc-4):nc)] SD$strata <- as.factor(paste2(IT)) #the 1st paste2
dataset$strata <- as.factor(paste2(dataset[, items.index])) #the 2nd paste2 key <- c(SD$z1);names(key) <- levels(SD$strata) DF <- transform(dataset, ability=round(key[strata], digits = digits)) DF$strata <- NULL
if (full){
return(DF)
} else {
return(DF\$ability)
}
}
#===========================================================================
##############
# TRY IT OUT #
##############
#This loads the paste2 function and a binary tests data set called dat
library(ltm)

#####################################################
# FIT A 1PL AND 2PL MODEL AND GET ABILITY ESTIMATES #
#####################################################
mod.2PL <- ltm(dat[, -c(1, 22)]~z1)    #fit a 2PL model
(FS2PL <- ltm::factor.scores(mod.2PL)) #obtain the ability scores

mod.1PLcon <- rasch(dat[, -c(1, 22)],  #fit a 2PL model
constraint = cbind(ncol(dat[, -c(1, 22)]) + 1, 1))
(FS1PLcon <- ltm::factor.scores(mod.1PLcon)) #obtain the ability scores
##############
# HERE IT IS #
##############
###############################################################################
# dataset -     This is the original data set you fit the model to.         #
#                 May have variables other than items.                        #
#                                                                             #
# items.index - This the item column numbers.  Can be supplied with         #
#                 the colon operator as in 2:21 or as a vector with concate   #
#                 as in c(1, 2, 3, 4, 5, 6, 7, 8, 9, ..., 21)                 #
#                                                                             #
# fact.score  - This is the object you assigned the factor.score outcome to #
###############################################################################
ability(dataset = dat, items.index = 2:21, fact.score = FS2PL)  #for the 2PL
(ab.1PL <- ability(dat, 2:21, FS1PLcon))                        #for the 1PL
######################################
# TO DO IT COMBINED; multiple models #
######################################
FSlist <- list(FS2PL, FS1PLcon)
LIST <- lapply(FSlist, function(x) ability(dat, 2:21, x, full=F))
new2 <- data.frame(dat, do.call('cbind', LIST))
names(new2)[names(new2)%in%c("X1", "X2")] <- c("ability_2PL", "ability_1PL")
head(new2)

In part III of this series we’ll explore a few more practical uses of the paste2 function!

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...