Tuesday, December 4, 2012

Session 4 - Perceptual Maps: R code and HW

Update:

Folks, the Session 4 HW is due on 14-Dec Friday (and not 10-December as was mistakenly stated in my email). Sorry about the confusion.

******************************************

Hi all,

I hope you had the chance to run the R demo of session 3 at home just to see first-hand R's ease-of-use in MKTR.

Before jumping into the R code for Session 3, first, a small admin step - you need to know how to download and install packages in R.

Say, you need the package 'MASS' installed. For the menu-driven option, go to the Packages Menu in the Menu bar, click on 'Install Package(s)...', a window will open asking which server to download the package from. Be patriotic and choose 'India' for our sole R repositary based in IIT-Chennai. Or choose any other country if the desi server is slow at a particular time.

A second window will open listing all the packages in R (at present, this list grows every month) in alphabetical order. Click on the package you want and sit back. R will automatically download and install the package for you. Might take a minute or two at most.

Well, either that or simply type:

install.packages("MASS")
OK, let's get started with the R codes then.

1. Simple Data Visualization using biplots. We use USArrests data (inbuilt R dataset) to see how it can be visualized in 2 dimensions. Just copy-paste the code below onto the R console [Hit 'enter' after the last line].

pc.cr <-princomp(USArrests, cor = TRUE)# scale data
summary(pc.cr)
biplot(pc.cr)
This is what the plot should look like. Click on image for larger view.

2. Code for making Joint Space maps I have coded a user-defined function called JSM in R. You can use it whenever you need to make joint space maps provided just by invoking the function. All it requires to work is a perceptions table and a preference rating table.

First copy-paste the entire block of code below onto your R console. Those interested in reading the code, pls copy-paste line-by-line. I have put explanations in comments ('#') for what the code is doing.

## --- Build func to run simple perceptual maps --- ##

JSM <- function(inp1, prefs){

# inp1 = perception matrix with row and column headers
# brands in rows and attributes in columns
# prefs = preferences matrix

par(pty="s") # set square plotting region

fit = prcomp(inp1, scale.=TRUE) # extract prin compts

plot(fit$rotation[,1:2], # use only top 2 prinComps
type ="n",xlim=c(-1.5,1.5), ylim=c(-1.5,1.5), # plot parms
main ="Joint Space map - Home-brew on R") # plot title

abline(h=0); abline(v=0) # build horiz & vert axes

attribnames = colnames(inp1)
brdnames = rownames(inp1)

# <-- insert attrib vectors as arrows--
for (i1 in 1:nrow(fit$rotation)){
arrows(0,0, x1=fit$rotation[i1,1]*fit$sdev[1], y1=fit$rotation[i1,2]*fit$sdev[2], col="blue", lwd=1.5);
text(x=fit$rotation[i1,1]*fit$sdev[1],y=fit$rotation[i1,2]*fit$sdev[2], labels=attribnames[i1],col="blue", cex=1.1)}

# <--- make co-ords within (-1,1) frame #

fit1=fit
fit1$x[,1]=fit$x[,1]/apply(abs(fit$x),2,sum)[1]
fit1$x[,2]=fit$x[,2]/apply(abs(fit$x),2,sum)[2]
points(x=fit1$x[,1], y=fit1$x[,2], pch=19, col="red")
text(x=fit1$x[,1], y=fit1$x[,2], labels=brdnames,col="black", cex=1.1)

# --- add preferences to map ---#
k1 = 2; #scale-down factor
pref=data.matrix(prefs)# make data compatible
pref1 = pref %*% fit1$x[,1:2]
for (i1 in 1:nrow(pref1)){segments(0,0, x1=pref1[i1,1]/k1,y1=pref1[i1,2]/k1, col="maroon2", lwd=1.25)}
# voila, we're done! #

}

3. OfficeStar MEXL example done on R

All the data for the below JSM examples are stored as tables in this google spreadsheet.

I use as my example the OfficeStar dataset that I also demo in class from MEXL's built-in examples database.To facilitate comparison, I use as input format in R the same tables that you would otherwise use in MEXL

Pls open the google doc and copy the average perceptions matrix (cell B5 to cell F10) onto a notepad and read it in the usual way.

Step 3a: Read in the attribute table into 'mydata'.

# -- Read in Average Perceptions table -- #
mydata = read.table(file.choose(), header = TRUE)
mydata = t(mydata) #transposing to ease analysis
mydata #view the table read
# extract brand & attribute names #
brdnames = rownames(mydata)
attribnames = colnames(mydata)

Step 3b: Read into R the preferences table into 'prefs' (cell C15 to F24 on the google spreadsheet) via the notepad.

# -- Read in preferences table -- #
pref = read.table(file.choose())
dim(pref) #check table dimensions
pref[1:10,] #view first 10 rows

Data reading is done. You should see the data read-in as in the figure above. We can start analysis now. Finally.

Step 3c: Run Analysis

JSM(mydata, pref)

That is it. That one function call executes the entire JSM sequence. The result can be seen in the image below. Again, the JSM function is generic and can be applied to *any* dataset in the input format we just saw to make joint space maps from.

4. Session 2 HW - JSM Analysis

This is *your* data from the session 2 HW surveys you had filled. You evaluated term 4 core courses along 5 attributes. Let's see if a JSM can throw more light on the perceptions and preferences of the Co2013 at Mohali in this regard.

First, read-in the data the usual way.

  • Read-in cells M5 to AF55 for the attribute perceptions matrix.
  • Then read-in cells H5 to K55 for the preferences matrix.
  • Note that the data format here is different from the input in the OfficeStar example. There we had the 'Average perceptions matrix'.
  • Here, the data is more 'raw'. It has to be processed and the averages computed and then tabulated. No problemo, we'll get R to process it for us.
  • Hence, I have separately entered the attribute and 'brand' names.
# now read in perceptions data (w/o headers)
mydata = read.table(file.choose())
dim(mydata); mydata[1:4,]

# read-in preferences matrix
prefs = read.table(file.choose())
dim(prefs); prefs[1:4,]

# name brands and attributes involved
attribs = c("PerspChange", "TheoryValue", "PracticalRelevance", "InterestStimulated", "DifficultyLevel")
brands = c("GSB", "INVA", "MGTO", "SAIT")

Note above that the attribute and brand names have no spaces in them.

Now, some more code to manipulate the data and build the input matrix in the right format. On your part, just copy-paste. if you want to understand the code, go line-by-line, else paste in a block.

# Build input matrix for Perceptual map
inp1 = matrix(0, nrow=length(attribs), ncol=length(brands))

a1 = apply(mydata, 2, mean)
a2 = seq(from=1, to=20, by=4)

for (i1 in 1:nrow(inp1)){ inp1[i1,] = a1[a2[i1]:(a2[i1]+ncol(inp1)-1)]}

colnames(inp1) = brands; rownames(inp1) = attribs; inp1
inp1 = t(inp1) # transpose for convenience
cor(inp1) # view correlations among the attribs

OK. Now to run the analysis. Again, just invoke JSM and it does the job.
Note:Use 'inp1' and 'prefs' as arguments to the JSM function because that is what we have named our average perceptions matrix and our preference matrix respectively.
JSM(inp1, prefs)

4. Applying JSM to select Subsets

In Session 4, we see that p-maps can mislead and confuse as much as enlighten. It's important that the transformation (e.g. taking averages) of perceptual data be meaningful. Hence, there may be occasion for us to require that we build JSMs on select subsets of the full dataset.

For instance, if we had reason to believe that males and females may perceive a given brand differently, then could we sort the dataset by gender and draw JSMs by gender?

The below function 'JSMsubset' allows us to sort on any column of interest and plot JSMs for each chosen subset.

### --- func to build inputs to JSM subsets ---- ###
JSMsubset <- function(mydata, prefs, attribs, brands, k1){

a1 = apply(mydata[k1,], 2, mean)
a2 = seq(from=1, to=length(a1), by=length(brands))

# define a new inp1
inp1 = matrix(0, nrow=length(attribs), ncol=length(brands))
for (i1 in 1:nrow(inp1)){ inp1[i1,] = a1[a2[i1]:(a2[i1]+ncol(inp1)-1)]}
colnames(inp1) = brands; rownames(inp1) = attribs; inp1

inp1 = t(inp1) # transpose for convenience
prefs1 = prefs[k1,]

outp = list(inp1, prefs1)

outp }
Henceforth, invoking JSMsubset() will produce an output that will then enable us to use JSM() proper to draw JSMs. Read in the gender variable (cells L5 to L55) into a dataset called 'demog' and follow the code below.
demog=read.table(file.choose())

attach(demog);
fem=(Gender=="Female")
male=(Gender!="Female")

k1 = fem
outp = JSMsubset(mydata, prefs, attribs, brands, k1)
JSM(outp[[1]], outp[[2]])
That was the female students' p-map. The one for male students follows.
k1 = male
outp = JSMsubset(mydata, prefs, attribs, brands, k1)
JSM(outp[[1]], outp[[2]])
OK, so I was quite mystified when I noted that the perceptions from Mohali seemed remarkably similar across attributes and courses. In contrast, the Hyd folks were all over the place. Later, it dawned that not all Hyd students had a uniform core courses experience. Different sections had different instructors and so on. Here, one instructor effectively handled all 3 sections.

BTW, how might you use JSMsubset for your coming HW? Well, imagine if you could sort by, say, workex or intended major or any other variable of interest and then draw JSMs. For instance:

k1=(pgid==61310076)
outp = JSMsubset(mydata, prefs, attribs, brands, k1)
JSM(outp[[1]], outp[[2]])

k1 = (workex > 4)
outp = JSMsubset(mydata, prefs, attribs, brands, k1)
JSM(outp[[1]], outp[[2]])

The real power of the above method will come after we go through session 5 - segmentation. Once we start segmenting a respondent base using basis variables of interest, then we can use JSMsubset to test around hither-tither.

4a. HW1 for Session 4 involving JSMsubsets.

About the data:

  • Open the HW dataset sent by email to you. Go to the worksheet 'HW1 JSM input data'.
  • Columns A to Z contain your perception and preference matrices. These data are already there in the google spreadsheet.
  • Columns AB to AI contain demographic information - workex(yrs), Gender, Education and Intended major. This is how typical qualtrics output would look like (after cleaning up).

Your task in Session 4 HW1 is to:

  • Plot any one student's JSM. Then plot another student's JSM. By trial and error find two students such that their JSMs show significant differences. Interpret the differences.
  • Split the Dataset into two - Those intending to major in marketing and Those not. Then plot JSMs for each of these 2 groups. Interpret differences if any.
  • Split the Dataset into two - Engineers versus non-engineers. Then plot JSMs for each of these 2 groups. Interpret differences if any.
Submission Format:

  • Create a plain white blank PPT
  • Write your name and PGID on the title slide
  • Copy-paste your JSM plots from R to the PPT(as metafiles)
  • After each JSM plot, explain yourinterpretation of the plot in bullet points in the next slide
  • Give an informative heading to each slide. E.g., 'JSM for student 10' or 'Interpreting student 10's JSM' etc.
  • Use the same format for HW2 and HW3 on MDS and factor analysis
  • Drop the PPT into the dropbox on LMS well before deadline (next Friday 14-Dec midnight).

In case you are wondering what is the value-add from this exercise, let me point out the learning goals that should all be well within grasp once you successfully navigate this part of your HW.

Click on the image for a larger size picture.

The MDS and factor analysis components of session 4 are in a separate blog-post as this one was getting unwieldy.

Sudhir


12 comments:

  1. Hi Prof,
    I have R version 2.15.2 and i am unable to download the package Mass, i have followed the code written above yet m facing the problem.
    Best,
    Asawari

    ReplyDelete
    Replies
    1. Hey Asawari

      Were you able to resolve your problem?

      I faced the same problem today. I guess if you right click on R and "Run as Administrator", you should be able to install Mass. Without Admin rights, it is not able to make changes in the Library folder.

      -Priyanka

      Delete
    2. That's useful to know. Thanks, Priyanka.

      Sudhir

      Delete
  2. Hi Asawari,

    Did you use capital letters 'MASS'? R is case-sensitive.

    If not, I'll ask Ankit to upload the windows binaries for all the packages on LMS. Will talk abt this in more detail in the R tutorial tomorrow.

    Sudhir

    ReplyDelete
  3. Dear Professor

    Facing some issues while doing JSM for homework. So when I try to type the code:
    k1=(pgid==61310076)
    outp = JSMsubset(mydata, prefs, attribs, brands, k1)
    JSM(outp[[1]], outp[[2]])

    k1 = (workex > 4)
    outp = JSMsubset(mydata, prefs, attribs, brands, k1)
    JSM(outp[[1]], outp[[2]])


    It is giving me an error as below;

    pgid=read.table(file.choose())
    > k1=(pgid==61310076)
    > outp = JSMsubset(mydata, prefs, attribs, brands, k1)
    > JSM(outp[[1]], outp[[2]])
    Error in prcomp.default(inp1, scale. = TRUE) :
    cannot rescale a constant/zero column to unit variance

    Can you help to figure if code is correct? I defined pgid in the read code ...

    Kruti

    ReplyDelete
    Replies
    1. Hi Kruti,

      Pls try some other PGIDs. In particular, ensure that none of the inputs (perceptions or preferences) have exactly the same values. For example, if 076 has input 5 5 5 5 5, then change it to 5.1, 4.9, 5.15, 4.85, 5 so that there is enough of variation in the perceptions for the program to run smoothly. Pls contact the AA Ankit for help in running R, he's good at debugging my code. I'm currently in Hyd and return sunday afternoon.

      Sudhir

      Delete
  4. I'll ask Ankit to upload a folder called 'Session 4 HWs' onto LMS.

    It will contain HW datasets in .txt format, one for each dataset. There will also be a 'R code.txt' notepad from which you can directly copy-paste the code for the datasets to get the HWs to run.

    This is a more convenient format Pls use that to get your HWs done quickly.

    Sudhir

    ReplyDelete
  5. OK, the folder is ready and sent to Ankit for uploading to LMS.

    Pls use the data and code in that folder to tide over your HWs (R portion) very quickly.

    Sudhir

    ReplyDelete
  6. Dear Professor,

    I have been struggling with the software. I have tried the demog file defined above and ran the subset function but got the following errors.

    > fem=(Gender=="Female")
    Error: object 'Gender' not found
    > male=(Gender!="Female")
    Error: object 'Gender' not found
    >

    Please let me know where and how to define the gender. I have simply copied the code written in the post above...

    Thanks

    ReplyDelete
  7. Hi Anon,

    Just type the following line in:

    Gender=demog

    and proceed. Let me know if it works.

    Sudhir

    ReplyDelete
  8. Hi Anon,


    Pls use the LMS uploaded folder 'session 4 HW'. It has both code and datasets. Copy paste code from there and read-in the datasets already present. It will be easier and faster.

    Pls drop by if you are in school at the moment. I amd in my office 114, at ext 1714.


    Sudhir
    Sudhir

    ReplyDelete
  9. Thanks Professor. It worked..

    ReplyDelete

Constructive feedback appreciated. Please try to be civil, as far as feasible. Thanks.