The Need for paste2 (part II)

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

About these ads

About tylerrinker

I am Literacy PhD student with a bent for the quantitative and a passion for R.
This entry was posted in paste and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s