Site icon R-bloggers

The Need for paste2 (part II)

[This article was first published on TRinker's R Blog » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

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
load(url("http://dl.dropbox.com/u/61803503/paste2demo1.RData"))
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
head(ab.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!

Click here for a .txt version of this script used here


To leave a comment for the author, please follow the link and comment on their blog: TRinker's R Blog » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.