Session 6 is done. We covered two main ways to map perceptual data - (i) using the attribute ratings (AR) method to create p-maps and joint-space maps (JSMs), and (ii) using the overall similarity (OS) approach to create multidimensional scaling (MDS) maps.We also saw some 101 stuff on positioning, definitional terms, common positioning startegies etc. The point was to get you thinking on how the mapping process could throw insights onto positioning in general, which strategy to adopt based on what criteria etc.
OK, next, what will follow is the code and snapshots of the plots that emerge from the classwork examples I did. Again, you are strongly encouraged to replicate the classwork examples at home. Copy-paste a only a few lines of code at a time after reading the comments next to each line of code. {P.S.- the statements following a '#' are for documentation purposes only and aren't executed}.So, without further ado, let us start right away:
##########################################
1. Simple Data Visualization using biplots: USArrests example.
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]. Need to install package "MASS". Don't reinstall if you have already installed it previously. A package once installed lasts forever.
rm(list = ls()) # clear workspace install.packages("MASS") # install MASS package mydata = USArrests # USArrests is an inbuilt dataset pc.cr = princomp(mydata, cor=TRUE) # princomp() is core func summary(pc.cr) # summarize the pc.cr object biplot(pc.cr) # plot the pc.cr object abline(h=0); abline(v=0) # draw horiz and vertical axes |
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){ #JSM() func opens
# inp1 = perception matrix with row and column headers 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 and 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=fitfit1$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) points(x = pref1[i1,1]/k1, y = pref1[i1,2]/k1, pch=19, col="maroon2") text(x = pref1[i1,1]/k1, y = pref1[i1,2]/k1, labels = rownames(pref)[i1], adj = c(0.5, 0.5), col ="maroon2", cex = 1.1)} # voila, we're done! #} # JSM() func ends
|
3. OfficeStar MEXL example done on R
Goto LMS folder 'Session 6 files'. The file 'R code officestar.txt' contains the code (which I've broken up into chunks and annotated below) and the files 'officestar data1.txt' and 'officestar pref data2.txt' contain the average perceptions or attribute table and preferences table respectively.
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 and attribute names # brdnames = rownames(mydata); attribnames = colnames(mydata) |
Step 3b: Read into R the preferences table into 'prefs'.
# -- Read in preferences table -- # pref = read.table(file.choose()) dim(pref) #check table dimensions pref[1:10,] #view first 10 rows |
Step 3c: Run Analysis
# creating empty pref dataset pref0 = pref*0; rownames(pref0) = NULL JSM(mydata, pref0) # p-map without prefs information |
The above code will generate a p-map (without the preference vectors). Should look like the image below (click for larger image):
However, to make true joint-space maps (JSMs), wherein the preference vectors are overlaid atop the p-map, run the one line code below:
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. Am sure you'll leverage the code for animating your project datasets. Let me or Ankit know in case any assistance is needed in this regard.
4. Session 2 survey Data on Core courses:
Lookup LMS folder 'session 6 files'. Save the data and code files to your machine. Data files are 'courses data.txt' for the raw data on perceptions and courses data prefs.txt' for the preference data with student names on it. Now let the games begin.
# read in data mydata = read.table(file.choose()) # 'courses data.txt' head(mydata) # I hard coded attribute and brand names attrib.names = c("will.recommend", "persp.change", "conceptual.value.add", "practical.relevance", "interest.sustained", "difficulty.level"); brand.names = c("GSB", "INVA", "MGTO", "SAIT") |
Should you try using your project data or some other dataset, you'll need to enter the brand and attribute names for that dataset in the same order in which they appear in the dataset, separately as given above.I then wrote a simple function, titled 'pmap.inp()' to denote "p-map input", to transform the raw data into a brands-attributes average peceptions table. Note that the below code is specific to the first set of columns being the preferences data.
# construct p-map input matrices using pmap.inp() func pmap.inp = function(mydata, attrib.names, brand.names){ #> pmap.inp() func opens a1 = NULL for (i1 in 1:length(attrib.names)){ start = (i1-1)*length(brand.names)+1; stop = i1*length(brand.names); a1 = rbind(a1, apply(mydata[,start:stop], 2, mean)) } # i1 loop ends rownames(a1) = attrib.names; colnames(a1) = brand.names a1 } # pmap.inp() func ends a1 = pmap.inp(mydata, attrib.names, brand.names)
|
And now, we're ready to run the analysis. First the p-mapo without the prefences and then the full JSM.
# now run the JSM func on data percep = t(a1[2:nrow(a1),]); percep # prefs = mydata[, 1:length(brand.names)] prefs = read.table(file.choose(), header = TRUE) # 'courses data prefs.txt' prefs1 = prefs*0; rownames(prefs1) = NULL # null preferences doc created JSM(percep, prefs1) # for p-map sans preferences |
Should produce the p-map below:
JSM(percep, prefs) # for p-map with preference data |
Should produce the JSM below:
5. Running MDS code with Car Survey Data:
The code is in 'R code HW dataset JSMs.txt' in LMS folder 'session 6 files'. The data are in 'mds car data raw.txt'. Read them in and follow the instructions here.
# --------------------- # ### --- MDS code ---- ### # --------------------- # rm(list = ls()) # clear workspace mydata = read.table(file.choose(), header = TRUE) # 'mds car data raw.txt' dim(mydata) # view dimension of the data matrix brand.names = c("Hyundai", "Honda", "Fiat", "Ford", "Chevrolet", "Toyota", "Nissan", "TataMotors", "MarutiSuzuki")
|
Note that I have hard-coded the brand names into 'brand.names' If you want to use this MDS code for another dataset (for your project, say) then you'll have to likewise hard-code the brand.names in.Next, I defined a function called run.mds() that takes as input the raw data and the brand names vector, runs the analysis and outputs the MDS map. Cool, or what..
### --- build user define func run.mds --- ### run.mds = function(mydata, brand.names){ # build distance matrix # k = length(brand.names) dmat = matrix(0, k, k) for (i1 in 1:(k-1)){ a1 = grepl(brand.names[i1], colnames(mydata));
for (i2 in (i1+1):k){a2 = grepl(brand.names[i2], colnames(mydata)); a3 = a1*a2; a4 = match(1, a3); dmat[i1, i2] = mean(mydata[, a4]); dmat[i2, i1] = dmat[i1, i2] } #i2 ends } # i1 ends colnames(dmat) = brand.names; rownames(dmat) = brand.names ### --- run metric MDS --- ### d = as.dist(dmat) # Classical MDS into k dimensions # fit = cmdscale(d,eig=TRUE, k=2) # cmdscale() is core MDS func fit # view results # plot solution #
x = fit$points[,1]; plot(x, y, xlab="Coordinate 1", ylab="Coordinate 2", main="Metric MDS", xlim = c(floor(min(x)), ceiling(max(x))), ylim = c(floor(min(y)), ceiling(max(y))), type="p",pch=19, col="red"); text(x, y, labels = rownames(fit$points), cex=1.1, pos=1); abline(h=0); abline(v=0)# horiz and vertical lines drawn } # run.mds func ends
|
Time now to finally invoke the run.mds func and get the analysis results:
# run MDS on raw data (before segmenting) run.mds(mydata, brand.names) |
The resulting MDS map looks like this:
OK, that's quite a bit now for classwork replication. Let me know if any code anywhere is not running etc due to any issues.
###################################
6. Session 6 HW:
This HW is also a group submission. You will need to co-operate with the rest of our group to get it done.
- JSM based homework:
- Collect basic demographic information about your group mates - #yrs of workex, previous industry, educational qualifications, intended major etc.
- Run individual level JSM analysis on each of your team mates (and youself) using the code below (place appropriate name in student.name = c("") in that code)
- Compare the JSMs you obtain - what salient similarities and differences do you see?
- Now, using the demographic data you have collected, speculate on which demographic characteristics are best able to explain at least some of the similarities and differences you see.
- Place (i) the 4 JSms, (ii) your list of salient similarities and differences (preferably in tabular form), (iii) the demographic profile of each group member (again, in tabular form) and (iv) the subset of demographic variables that best explain the JSMs in a PPT.
- MDS based homework:
- Construct individual level MDS maps for yourself and your group members.
- Interpret them. In particular try to see what the axes might mean.
- Interpret the clusters of similar brands (brands bunched close together) in terms of what characteristics are common among them.
- Collate your (i) MDS plots, (ii) axes interpretation on each plot and (iii) similarity cluster interpretation on each plot into a PPT
- Submit one PPT for both parts of your homework. Title slide should contain group name and member names + PGIDs. Name the slide as
_session6HW.pptx -
- Note: If you don't find your name in the dataset, use a friend's observation (and demographic data) instead.
student.name = c("Himanshu") # say, student's name is Himanshu # retain only that row in the raw data which has name 'Himanshu' mydata.test = mydata[(rownames(prefs) == student.name),] # run the pmap.inp() func to build avg perceptions table a1.test = pmap.inp(mydata.test, attrib.names, brand.names); percep.test = t(a1.test[2:nrow(a1.test),]);
# introduce a small perturbation lest matrix not be of full rank prefs.test = prefs[(rownames(prefs) == student.name),]; prefs.test # run analysis on percep.test and prefs.test JSM(percep.test, prefs.test) |
Use code below to run individual level MDS plots. Just place the apropriate student.name and run.
student.name = c("Himanshu") #change student name as reqd # retain only that row in raw data with name Himanshu mydata.test = mydata[(rownames(mydata) == student.name),]; # run analysis and save result by copy pasting onto PPT run.mds(mydata.test, brand.names) |
No comments:
Post a Comment
Constructive feedback appreciated. Please try to be civil, as far as feasible. Thanks.