R Markdown
Perceptual maps are a great way to visualize where a brand stands in
relation to it’s competitors and is a useful tool to gain a marketing
advantage. If a brand aspires to be associated with certain attributes
or gain ground on a competitor a perceptual map is a great way to know
where you are in the minds of customers and allocate marketing resources
accordingly.
Read in the data file
# create path object
path <- "g:/Portfolio Projects/P-Maps/Source Data/CARS DATA.xlsx"
# get the sheet names
sheets.names<- excel_sheets(path)
# list of all sheets' contents
sheets<- lapply(excel_sheets(path), read_excel, path = path)
## New names:
## • `` -> `...1`
# convert each object in list (the sheets...) to workable dataframe
dfs<- lapply(sheets,as.data.frame)
# name the list objects using the sheet names extracted above
names(dfs) <- sheets.names
# rename the first column in each dataframe to "Attributes"
for(i in 1:length(dfs)){
colnames(dfs[[i]])[1] <- "Attributes"
# create data.frame objects from each item in list (each sheet in the excel workbook)
x <- dfs[[i]]
eval(parse(text = paste(names(dfs)[[i]],"<- x")))
}
View the data
# examine column labels
names(CARS)
## [1] "Attributes" "Lexus" "Audi" "Land Rover" "Genesis"
## [6] "Cadillac" "BMW"
# view the data table
kable(CARS, caption = "Examine the source data")
Examine the source data
| Status and Prestige |
0.21 |
0.22 |
0.26 |
0.57 |
0.63 |
0.24 |
| Emotional Fulfillment |
0.53 |
0.62 |
0.62 |
0.61 |
0.43 |
0.54 |
| Passion |
0.69 |
0.53 |
0.22 |
0.45 |
0.54 |
0.63 |
| Elegance |
0.27 |
0.68 |
0.42 |
0.42 |
0.35 |
0.26 |
| Exclusivity |
0.27 |
0.70 |
0.47 |
0.55 |
0.43 |
0.22 |
| Performance |
0.41 |
0.35 |
0.66 |
0.56 |
0.47 |
0.63 |
| Comfort |
0.29 |
0.27 |
0.61 |
0.21 |
0.45 |
0.54 |
| Craftsmanship |
0.29 |
0.21 |
0.27 |
0.47 |
0.45 |
0.68 |
| Sophistication |
0.34 |
0.43 |
0.28 |
0.61 |
0.23 |
0.31 |
| Security |
0.29 |
0.65 |
0.58 |
0.44 |
0.38 |
0.68 |
| Individuality |
0.60 |
0.68 |
0.48 |
0.28 |
0.24 |
0.47 |
| Timelessness |
0.46 |
0.53 |
0.25 |
0.55 |
0.45 |
0.32 |
Prepare for the principle component analysis (PCA)
################################## Global data
# store the attribute names
Global.names<- CARS$Attributes
# select and standardize data, need to subset the data to perform the following tranformations
# data must be only numeric, the attributes are added back in later as column headers
# subset the data to exclude the attribute column
Global<- CARS[2:length(CARS)]
# ensure all values are numeric by converting
Global <- as.data.frame(sapply(Global, as.numeric))
str(Global)
## 'data.frame': 12 obs. of 6 variables:
## $ Lexus : num 0.21 0.53 0.69 0.27 0.27 0.41 0.29 0.29 0.34 0.29 ...
## $ Audi : num 0.22 0.62 0.53 0.68 0.7 0.35 0.27 0.21 0.43 0.65 ...
## $ Land Rover: num 0.26 0.62 0.22 0.42 0.47 0.66 0.61 0.27 0.28 0.58 ...
## $ Genesis : num 0.57 0.61 0.45 0.42 0.55 0.56 0.21 0.47 0.61 0.44 ...
## $ Cadillac : num 0.63 0.43 0.54 0.35 0.43 0.47 0.45 0.45 0.23 0.38 ...
## $ BMW : num 0.24 0.54 0.63 0.26 0.22 0.63 0.54 0.68 0.31 0.68 ...
# calculate row means
rowmean<- rowMeans(Global)
rowmean
## [1] 0.3550000 0.5583333 0.5100000 0.4000000 0.4400000 0.5133333 0.3950000
## [8] 0.3950000 0.3666667 0.5033333 0.4583333 0.4266667
# set multiplier
standard <- 100
# subtract each value by the row mean
new.Global <- sweep(Global, 1, rowmean,"-")
# multiply each value by 100
Global.map <- sweep(new.Global, 2, standard,"*")
# transpose
Global.map.t <- as.data.frame(t(Global.map))
# set column name for attributes
colnames(Global.map.t) <- Global.names
# let's take a look at the transposed data
kable(Global.map.t, caption = "Transposed data for the PCA")
Transposed data for the PCA
| Lexus |
-14.5 |
-2.833333 |
18 |
-13 |
-17 |
-10.333333 |
-10.5 |
-10.5 |
-2.666667 |
-21.333333 |
14.166667 |
3.333333 |
| Audi |
-13.5 |
6.166667 |
2 |
28 |
26 |
-16.333333 |
-12.5 |
-18.5 |
6.333333 |
14.666667 |
22.166667 |
10.333333 |
| Land Rover |
-9.5 |
6.166667 |
-29 |
2 |
3 |
14.666667 |
21.5 |
-12.5 |
-8.666667 |
7.666667 |
2.166667 |
-17.666667 |
| Genesis |
21.5 |
5.166667 |
-6 |
2 |
11 |
4.666667 |
-18.5 |
7.5 |
24.333333 |
-6.333333 |
-17.833333 |
12.333333 |
| Cadillac |
27.5 |
-12.833333 |
3 |
-5 |
-1 |
-4.333333 |
5.5 |
5.5 |
-13.666667 |
-12.333333 |
-21.833333 |
2.333333 |
| BMW |
-11.5 |
-1.833333 |
12 |
-14 |
-22 |
11.666667 |
14.5 |
28.5 |
-5.666667 |
17.666667 |
1.166667 |
-10.666667 |
PCA
# FINAL Global map data
prcomp_Global<- prcomp(Global.map.t)
colnames(Global.map.t)
## [1] "Status and Prestige" "Emotional Fulfillment" "Passion"
## [4] "Elegance" "Exclusivity" "Performance"
## [7] "Comfort" "Craftsmanship" "Sophistication"
## [10] "Security" "Individuality" "Timelessness"
# plot the PCA object
Global.plot <- autoplot(prcomp_Global,geom = 'path', data = Global.map.t,
label = TRUE, label.vjust=-.5, label.colour = 'black', label.size = 5,
loadings = TRUE, loadings.label = TRUE, loadings.label.vjust=-.5, loadings.colour = 'gray', loadings.label.colour = 'black',
loadings.label.size = 4)
Global.plot

Rotations
If the client wants attributes or brands in a certain quadrant, we
have a few options for rotation
Let’s flip the plot around for fun
# set the astetics of the plot
# there are several themes to use, void is simple and removes all elements of the plot
Global.plot<- Global.plot + theme_void()
Global.plot

############### rotate plot, comments are relative to original plot
# rotate left to right
Global.plot.1 <- Global.plot + scale_x_reverse()
Global.plot.1

# rotate on axis top left to bottom right
Global.plot.2 <- Global.plot + coord_flip()
Global.plot.2

# rotate on axis top to bottom
Global.plot.3 <- Global.plot + scale_y_reverse()
Global.plot.3

# select plot to export to PowerPoint, we'll just stick with the original plot
which.Global.plot <- Global.plot
which.Global.plot

Export your pretty plot to PowerPoint!
# create editable ppt
doc <-read_pptx()
doc <- add_slide(doc, layout = "Title and Content", master = "Office Theme")
doc <- ph_with(doc,value = "Perceptual Map", location = ph_location_type(type = "title"))
doc <- ph_with(doc,value = "Slide 1", location = ph_location_type(type = "sldNum"))
doc <- ph_with(doc, dml(ggobj = which.Global.plot), location = ph_location_type(type = "body"))
################################## Global
# final ppt document
print(doc, target = "g:/Portfolio Projects/P-Maps/Cars Data.pptx")