Los mapas perceptuales constituyen una de las herramientas más habituales del marketing analítico. De acuerdo a la definición de Wikipedia:

  El mapeado perceptual es una técnica de análisis multidimensional utilizada para representar gráficamente la percepción de los encuestados en un estudio, teniendo en cuenta dos o más dimensiones percibidas, generalmente sobre un producto. Los productos se perciben de muchas maneras; es decir, se toma en cuenta más de una característica de estímulo. Los consumidores llenan escalas de medición para expresar sus percepciones de las múltiples características y semejanzas que presentan las distintas marcas. Se analizan los resultados y pueden graficarse en "mapas perceptuales" con un sistema de coordenadas que indican cómo el público percibe las marcas y sus diferencias.

Los mapas perceptuales (también llamados mapas de posicionamiento de productos) pueden tener una cantidad arbitraria de dimensiones, sin embargo y por una cuestión de simplicidad suelen utilizarse solo 2 dimensiones.

Estos son algunos de los motivos por los que utilizamos los mapas perceptuales:

Un ejemplo de percepción de la marca de coches.

El paquete plfm incluye un conjunto de datos respecto de la opinión de 78 encuestados acerca de la opinión de sobre 27 atributos de 14 modelos de coche de fabricación europea. A continuación cargamos los datos en R:

# install.packages('plfm')
library(plfm)
## Loading required package: sfsmisc
## Loading required package: abind
data(car)
str(car)
## List of 3
##  $ data   :'data.frame': 29484 obs. of  6 variables:
##   ..$ IDobject      : num [1:29484] 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ objectlabel   : Factor w/ 14 levels "Audi A4","BMW X5",..: 13 13 13 13 13 13 13 13 13 13 ...
##   ..$ IDattribute   : num [1:29484] 1 2 3 4 5 6 7 8 9 10 ...
##   ..$ attributelabel: Factor w/ 27 levels "Agile","Attractive",..: 5 1 6 19 18 8 26 9 12 20 ...
##   ..$ IDrater       : num [1:29484] 1 1 1 1 1 1 1 1 1 1 ...
##   ..$ rating        : num [1:29484] 1 0 0 1 1 1 1 1 0 0 ...
##  $ freq1  : num [1:14, 1:27] 29 49 7 42 1 21 17 21 16 2 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:14] "Volkswagen Golf" "Opel Corsa" "Nissan Qashgai" "Toyota Prius" ...
##   .. ..$ : chr [1:27] "Economical" "Agile" "Environmentally friendly" "Reliable" ...
##  $ freqtot: num [1:14, 1:27] 78 78 78 78 78 78 78 78 78 78 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:14] "Volkswagen Golf" "Opel Corsa" "Nissan Qashgai" "Toyota Prius" ...
##   .. ..$ : chr [1:27] "Economical" "Agile" "Environmentally friendly" "Reliable" ...
head(car$freq1,2)
##                 Economical Agile Environmentally friendly Reliable
## Volkswagen Golf         29    40                       20       58
## Opel Corsa              49    36                       16       25
##                 Practical Family Oriented Versatile
## Volkswagen Golf        44              12        25
## Opel Corsa             43               8         6
##                 Good price-quality ratio Luxurious Safe Sporty Attractive
## Volkswagen Golf                       30        12   40     29         33
## Opel Corsa                            43         1   19      8          9
##                 Comfortable Powerful Status symbol Technically advanced
## Volkswagen Golf          27       20            23                   10
## Opel Corsa               11        0             3                    1
##                 Sustainable Original Nice design Value for the money
## Volkswagen Golf          43        5          20                  24
## Opel Corsa               16        2           9                  29
##                 High trade-in value Exclusive Popular Outdoor Green
## Volkswagen Golf                  41         0      55       6     6
## Opel Corsa                        2         4      34       4     5
##                 City focus Workmanship
## Volkswagen Golf         30          14
## Opel Corsa              51           3

Como la base de datos es extensa, vamos a centrarnos en 6 modelos de coches exclusivamente:

selected.cars=t(car$freq1[c(14,11,7,5,1,4),])

Para realizar un mapa perceptual tendremos que primero hacer PCA sobre la matriz de datos y a continuación utilizar el comando biplot()

pca <- princomp(selected.cars)

biplot(pca,xlim=c(-0.75,0.75))

plot of chunk unnamed-chunk-3

Interpretación:
Un mapa perceptual (o biplot en lenguaje estadístico) es una representación de la información de una matriz de datos rectangular en la que las filas (observaciones) y las columnas (variables) se representan como puntos en un mismo espacio (en general de dimensión 2). En el output precedente, las variables (columnas) están representadas en color rojo y los datos (filas) en negro.
  - El origen (al centro) representa el valor medio de cada variable, una observación alejada del centro en una dirección determinada representa un valor lejano en término del centro para esa variable.
  - Para reconstruir la distancia entre dos observaciones con respecto a una variable en particular hay que proyectar ortogonalmente las observaciones sobre el eje en el que se representa a dicha variable. 
  - El ángulo entre los ejes en los que se representan dos variables representa el grado de correlación entre las variables.
  - La longitud de cada eje representa cuan bien esta esa variable representada en el biplot.

Para más detalles sobre como se construye un biplot se recomienda leer el tutorial del profesor GREENACRE.

Como en el gráfico anterior hay demasiadas observaciones podemos intentar hacer “zoom”sobre las zonas que nos interesan para el análisis. Por ejemplo, si comparamos la percepción de los clientes entre los modelos: “Volkswagen Golf” y “Toyota Prius” utilizamos xlim y ylim para enfocar en esta región del gráfico:

biplot(pca, expand=1, xlim=c(-.3,0.1),ylim=c(-.2,0) )

plot of chunk unnamed-chunk-4

Existe una gran variedad de paquetes en R que realizan de manera automática el mapa perceptual, por ejemplo el paquete anacor puede utilizarse de manera alternativa y obtendremos el siguiente resultado:

# install.packages('anacor') # Ejecuta esta línea de código solo una vez!
library(anacor)
## Loading required package: rgl
## Loading required package: splines
ca=anacor(selected.cars)
plot(ca, conf=NULL, main='Mapa Perceptual de Modelos de Coches Europeos')

plot of chunk unnamed-chunk-5

Este mapa es conocido para aquellos que trabajan en la industria automotriz. Vamos a dividir el mapa en 4 zonas: El cuadrante I representa los autos deportivos, el cuadrante II los económicos, el cuadrante III los familiares, y el cuadrante IV los coches de lujo. Otra perspectiva se obtiene si miramos como dimensión economía-lujo de arriba a la derecha hacia abajo a la izquierda y familiar-deportivo en el eje que va desde abajo a la izquierda hacia arriba a la derecha (i.e., haciendo una gran X sobre el gráfico).

A continuación veremos otros ejemplos de mapas perceptuales para seguir explorando las opciones de R.

US arrest data

Anteriormente hemos explorado el conjunto de datos US-arrest para hacer PCA:

data(USArrests)
head(USArrests)
##            Murder Assault UrbanPop Rape
## Alabama      13.2     236       58 21.2
## Alaska       10.0     263       48 44.5
## Arizona       8.1     294       80 31.0
## Arkansas      8.8     190       50 19.5
## California    9.0     276       91 40.6
## Colorado      7.9     204       78 38.7
US.pca <- princomp(USArrests, scale=T)
plot(US.pca)

plot of chunk unnamed-chunk-6

Vamos a ver ahora como representar estos datos en un biplot (un mapa perceptual)

biplot(US.pca)

plot of chunk unnamed-chunk-7

Cuando la información es difícil de leer en el gráfico (en este caso producto de la cantidad de información) podemos utilizar otras librerías, como ggplot2, para mostrar de manera más organizada el output. En este caso creamos una función que se llama PCbiplot que dado un las componentes principales (input) me devuelve el gráfico biplot respectivo.

# My own biplot function:
PCbiplot <- function(PC, x="PC1", y="PC2", colors=c('black', 'black', 'red', 'red')) {
    # PC being a prcomp object
    data <- data.frame(obsnames=row.names(PC$x), PC$x)
    plot <- ggplot(data, aes_string(x=x, y=y)) + geom_text(alpha=.4, size=3, aes(label=obsnames), color=colors[1])
    plot <- plot + geom_hline(aes(0), size=.2) + geom_vline(aes(0), size=.2, color=colors[2])
    datapc <- data.frame(varnames=rownames(PC$rotation), PC$rotation)
    mult <- min(
        (max(data[,y]) - min(data[,y])/(max(datapc[,y])-min(datapc[,y]))),
        (max(data[,x]) - min(data[,x])/(max(datapc[,x])-min(datapc[,x])))
        )
    datapc <- transform(datapc,
            v1 = .7 * mult * (get(x)),
            v2 = .7 * mult * (get(y))
            )
    plot <- plot + coord_equal() + geom_text(data=datapc, aes(x=v1, y=v2, label=varnames), size = 5, vjust=1, color=colors[3])
    plot <- plot + geom_segment(data=datapc, aes(x=0, y=0, xend=v1, yend=v2), arrow=arrow(length=unit(0.2,"cm")), alpha=0.75, color=colors[4])
    plot
}

En el caso de los datos US-arrest:

# install.packages('ggplot2')
library(ggplot2)
library(grid) # vamos a necesitar esta librería
PC.US.arrest <- prcomp(USArrests, scale=T)
PCbiplot(PC.US.arrest, colors=c("black", "black", "red", "yellow"))

plot of chunk unnamed-chunk-9

Otros paquetes de R para realizar el análisis de Correspondencias (biplots, mapas perceptuales):

Vamos a utilizar, por último, el conjunto de datos author del paquete de R “ca”. Esta matriz de datos contiene las frecuencias con las que se usan las 26 letras del alfabeto en 12 novelas americanas. Cada fila (que representa una novela) contiene simplemente la frecuencia absoluta de cada una de las 26 letras (columnas).

# install.packages('FactoMineR')
# install.packages('ca')

library(ca)
library(FactoMineR)

data(author)
head(author)
##                                a   b   c   d    e   f   g   h   i j  k   l
## three daughters (buck)       550 116 147 374 1015 131 131 493 442 2 52 302
## drifters (michener)          515 109 172 311  827 167 136 376 432 8 61 280
## lost world (clark)           590 112 181 265  940 137 119 419 514 6 46 335
## east wind (buck)             557 129 128 343  996 158 129 571 555 4 76 291
## farewell to arms (hemingway) 589  72 129 339  866 108 159 449 472 7 59 264
## sound and fury 7 (faulkner)  541 109 136 228  763 126 129 401 520 5 72 280
##                                m   n   o   p q   r   s   t   u   v   w  x
## three daughters (buck)       159 534 516 115 4 409 467 632 174  66 155  5
## drifters (michener)          146 470 561 140 4 368 387 632 195  60 156 14
## lost world (clark)           176 403 505 147 8 395 464 670 224 113 146 13
## east wind (buck)             247 479 509  92 3 413 533 632 181  68 187 10
## farewell to arms (hemingway) 158 504 542  95 0 416 314 691 197  64 225  1
## sound and fury 7 (faulkner)  209 471 589  84 2 324 454 672 247  71 160 11
##                                y  z
## three daughters (buck)       150  3
## drifters (michener)          137  5
## lost world (clark)           162 10
## east wind (buck)             184  4
## farewell to arms (hemingway) 155  2
## sound and fury 7 (faulkner)  280  1
# Usamos el paquete CA (FactorMineR) para el análisis de correspondencias 
ca2 = CA(author, graph = FALSE)
ca2
## **Results of the Correspondence Analysis (CA)**
## The row variable has  12  categories; the column variable has 26 categories
## The chi square of independence between the two variables is equal to 1567 (p-value =  1.578e-179 ).
## *The results are available in the following objects:
## 
##    name              description                   
## 1  "$eig"            "eigenvalues"                 
## 2  "$col"            "results for the columns"     
## 3  "$col$coord"      "coord. for the columns"      
## 4  "$col$cos2"       "cos2 for the columns"        
## 5  "$col$contrib"    "contributions of the columns"
## 6  "$row"            "results for the rows"        
## 7  "$row$coord"      "coord. for the rows"         
## 8  "$row$cos2"       "cos2 for the rows"           
## 9  "$row$contrib"    "contributions of the rows"   
## 10 "$call"           "summary called parameters"   
## 11 "$call$marge.col" "weights of the columns"      
## 12 "$call$marge.row" "weights of the rows"
# Matriz con auto-vectores
ca2$eig
##        eigenvalue percentage of variance cumulative percentage of variance
## dim 1   0.0076639                40.9070                             40.91
## dim 2   0.0036883                19.6870                             60.59
## dim 3   0.0024112                12.8702                             73.46
## dim 4   0.0013828                 7.3811                             80.85
## dim 5   0.0010017                 5.3465                             86.19
## dim 6   0.0007233                 3.8609                             90.05
## dim 7   0.0006586                 3.5154                             93.57
## dim 8   0.0004548                 2.4278                             96.00
## dim 9   0.0003739                 1.9958                             97.99
## dim 10  0.0002631                 1.4041                             99.40
## dim 11  0.0001132                 0.6042                            100.00
# Coordenadas de las filas
head(ca2$col$coord)
##       Dim 1    Dim 2    Dim 3     Dim 4     Dim 5
## a  0.001543 -0.01945  0.01328 -0.024088  0.014040
## b  0.086183 -0.02417 -0.05642  0.060250  0.012792
## c  0.185157 -0.08341  0.05553  0.035473  0.034392
## d -0.168576 -0.06895 -0.01441  0.008886  0.005076
## e  0.007592 -0.04159 -0.04929 -0.013595  0.004841
## f  0.111752 -0.04451  0.01898  0.016396 -0.049299
# Gráfica del mapa perceptual:
plot(ca2)

plot of chunk unnamed-chunk-10

En este gráfico también podemos ver que porcentaje de la variabilidad total de los datos se explican con cada una de las dimensiones utilizadas (en este caso, en total 62% en total).