Mapas Perceptuais com PCA: estudo de marcas

1 Objetivos

Nesta análise, vamos construir mapas perceptuais de marcas por meio da Análise de Componentes Principais (PCA). O objetivo é reduzir nove atributos avaliados em escala de 1 a 10 para poucas dimensões interpretáveis, preservando a maior parte possível da variabilidade e oferecendo insights sobre similaridade entre marcas.

Vamos usar a base brand.csv (100 respondentes, 10 marcas aj, atributos: perform, leader, latest, fun, serious, bargain, value, trendy, rebuy).

  • Características das marcas: perguntas
Atributo Exemplo de pergunta
`perform` Marca tem um forte desempenho?
`leader` Marca é líder no mercado?
`latest` Marca tem os produtos mais recentes?
`fun` Marca é divertida?
`serious` Marca é séria?
`bargain` Produtos da marca são uma pechincha?
`value` Produtos da marca possuem um bom valor?
`trendy` Marca está na moda?
`rebuy` Eu compraria a marca novamente?

2 Preparação e inspeção dos dados

load <- function(pkg){
  new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
  if (length(new.pkg))
    install.packages(new.pkg, dependencies = TRUE)
  sapply(pkg, require, character.only = TRUE)
} 

## Pacotes utilizados nessa análise

packages = c("tidyverse", "factoextra", "psych", "gridExtra", "readr", "janitor", "ggrepel", "patchwork", "corrplot", "corrr", "igraph", "ggraph")
load(packages)
 tidyverse factoextra      psych  gridExtra      readr    janitor    ggrepel 
      TRUE       TRUE       TRUE       TRUE       TRUE       TRUE       TRUE 
 patchwork   corrplot      corrr     igraph     ggraph 
      TRUE       TRUE       TRUE       TRUE       TRUE 

2.1 Leitura dos dados

path <- "https://raw.githubusercontent.com/tiagomartin/est014/refs/heads/master/dados/brand.csv"
brands <- read_csv(path, show_col_types = FALSE) %>%
  clean_names() 

brands %>% 
  glimpse()
Rows: 1,000
Columns: 10
$ perform <dbl> 2, 1, 2, 1, 1, 2, 1, 2, 2, 3, 2, 1, 3, 1, 3, 3, 2, 3, 2, 2, 2,…
$ leader  <dbl> 4, 1, 3, 6, 1, 8, 1, 1, 1, 1, 1, 2, 3, 5, 1, 2, 1, 8, 5, 3, 2,…
$ latest  <dbl> 8, 4, 5, 10, 5, 9, 5, 7, 8, 9, 5, 7, 10, 7, 3, 7, 6, 9, 10, 9,…
$ fun     <dbl> 8, 7, 9, 8, 8, 5, 7, 5, 10, 8, 6, 7, 10, 10, 6, 6, 7, 9, 8, 10…
$ serious <dbl> 2, 1, 2, 3, 1, 3, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 2, 4, 2, 2, 1,…
$ bargain <dbl> 9, 1, 9, 4, 9, 8, 5, 8, 7, 3, 1, 3, 3, 1, 3, 10, 1, 7, 6, 2, 5…
$ value   <dbl> 7, 1, 5, 5, 9, 7, 1, 7, 7, 3, 1, 2, 3, 3, 4, 5, 3, 10, 10, 6, …
$ trendy  <dbl> 4, 2, 1, 2, 1, 1, 1, 7, 5, 4, 1, 1, 3, 3, 4, 1, 5, 4, 5, 5, 3,…
$ rebuy   <dbl> 6, 2, 6, 1, 1, 2, 1, 1, 1, 1, 2, 5, 3, 1, 2, 3, 1, 2, 2, 2, 2,…
$ brand   <chr> "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a…
brands %>% 
  summary()
    perform           leader           latest            fun        
 Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   : 1.000  
 1st Qu.: 1.000   1st Qu.: 2.000   1st Qu.: 4.000   1st Qu.: 4.000  
 Median : 4.000   Median : 4.000   Median : 7.000   Median : 6.000  
 Mean   : 4.488   Mean   : 4.417   Mean   : 6.195   Mean   : 6.068  
 3rd Qu.: 7.000   3rd Qu.: 6.000   3rd Qu.: 9.000   3rd Qu.: 8.000  
 Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :10.000  
    serious          bargain           value            trendy     
 Min.   : 1.000   Min.   : 1.000   Min.   : 1.000   Min.   : 1.00  
 1st Qu.: 2.000   1st Qu.: 2.000   1st Qu.: 2.000   1st Qu.: 3.00  
 Median : 4.000   Median : 4.000   Median : 4.000   Median : 5.00  
 Mean   : 4.323   Mean   : 4.259   Mean   : 4.337   Mean   : 5.22  
 3rd Qu.: 6.000   3rd Qu.: 6.000   3rd Qu.: 6.000   3rd Qu.: 7.00  
 Max.   :10.000   Max.   :10.000   Max.   :10.000   Max.   :10.00  
     rebuy           brand          
 Min.   : 1.000   Length:1000       
 1st Qu.: 1.000   Class :character  
 Median : 3.000   Mode  :character  
 Mean   : 3.727                     
 3rd Qu.: 5.000                     
 Max.   :10.000                     

De forma geral, observa-se que os atributos mais “positivos” em média são os relacionados à modernidade/diversão da marca (latest ≈ 6,2 e fun ≈ 6,1), enquanto atributos ligados a recompra (rebuy ≈ 3,7) e preço/valor percebido (bargain e value ≈ 4,3) apresentam avaliações mais baixas. Além disso, vários atributos têm 1º quartil baixo (ex.: perform Q1 = 1; bargain/value Q1 = 2), sugerindo que há uma parcela de consumidores que de fato avalia marca(s) de forma bem negativa em alguns aspectos. Esse padrão indica que a PCA provavelmente encontrará uma dimensão relacionada à inovação/modernidade e outra relacionada a valor/preço e recompra, uma vez que esses conjuntos de atributos apresentam distribuições centrais distintas e potencialmente estruturadas em blocos de correlação.

2.2 Visualização exploratória

attr_names <- setdiff(names(brands), "brand")

X <- brands %>% select(all_of(attr_names))

X_long <- brands %>%
pivot_longer(all_of(attr_names),
names_to = "atributo", values_to = "nota")

# Guardar a coluna de marca (fator) separada
brand_fac <- brands %>% mutate(brand = as.factor(brand)) %>% pull(brand)

# Padronizar as variáveis
X_scaled <- scale(X)
df_scaled <- data.frame(brand_fac = brand_fac, X_scaled)

# histogramas facetados
p_hist <- ggplot(X_long, aes(nota)) +
geom_histogram(bins = 9, color = "white") +
facet_wrap(~ atributo, scales="free_y") +
labs(title = "Distribuição dos atributos (histogramas)") +
theme_minimal()


p_hist

Observa-se que a maior parte dos atributos tem uma massa grande de notas baixas (1 a 4), exceto latest, fun e (em menor grau) trendy, que apresentam caudas mais fortes para notas altas. Isso sugere que a percepção média de “inovação/modernidade/diversão” tende a ser mais positiva do que a percepção de “valor/preço/desempenho”. Além disso, rebuy é visivelmente o mais “puxado” para notas muito baixas, indicando que a disposição em recomprar é o atributo mais crítico (e possivelmente o mais difícil de conquistar), o que antecipa que a PCA provavelmente vai separar dimensões ligadas a modernidade/diversão versus valor/preço e recompra.

# boxplots facetados por atributo
p_box <- ggplot(X_long, aes(x = atributo, y = nota)) +
geom_boxplot() +
coord_flip() +
labs(title = "Distribuição dos atributos (boxplots)") +
theme_minimal()


p_box

O boxplot reforça o padrão visto nos histogramas: os atributos ligados a “inovação/diversão” (latest, fun, trendy) apresentam medianas mais altas e intervalos interquartílicos deslocados para a direita, enquanto atributos relacionados a valor/preço (bargain, value) e especialmente rebuy permanecem com centrais mais baixas. Além disso, há bastante dispersão em todos os atributos, sugerindo heterogeneidade real na percepção das marcas. Esse contraste estrutural entre atributos “mais modernos” e atributos “valor/recompra” é exatamente o tipo de padrão latente que a PCA tende a capturar, separando dimensões latentes distintas no mapa perceptual.

2.3 Matriz de correlações

cormat <- cor(X)
corrplot(cormat, method = "color", type = "upper", addCoef.col = "black",
tl.col = "black", tl.srt = 45, number.cex = .6,
title = "Matriz de correlações entre atributos")

A matriz de correlações mostra claramente dois sub-blocos relevantes: (i) bargain e value são fortemente correlacionados (0,74), compondo um núcleo evidente de “valor/preço percebido”; (ii) latest e trendy também se correlacionam positivamente (0,63), sugerindo um eixo de “modernidade/moda”. Além disso, rebuy correlaciona moderadamente com value (0,51) e perform (0,31), indicando que intenção de recompra parece ancorar-se tanto em percepção de valor quanto em desempenho.

tidy_cors <- X %>%
  correlate() %>%
  stretch()
graph_cors <- tidy_cors %>%
  filter(abs(r) > .3) %>%
  graph_from_data_frame(directed = FALSE)

ggraph(graph_cors) + geom_edge_link() + geom_node_point() +   ## Variaveis aparentam se agrupar em dois grupos
  geom_node_text(aes(label = name))

A visualização em rede ajuda a enxergar que os atributos não formam um único bloco homogêneo: existe um cluster bem definido formado por latest, trendy, value e bargain, o que reforça a ideia de um eixo “moda/modernidade/valor”. Em paralelo, perform, leader e serious aparecem mais conectados entre si, sugerindo outra dimensão ligada a “desempenho/liderança/seriedade”. rebuy fica numa posição intermediária, fazendo a ponte entre esses dois polos, o que é coerente com a lógica de que intenção de recompra é influenciada tanto pela percepção de modernidade quanto pela percepção de valor/desempenho.


3 Construção das componentes principais

PCA é sensível a escala. Como nossos atributos são todos numa escala comum (1–10), poderíamos usar a matriz de correlações. Isso facilita a interpretação dos loadings como correlações entre variável e componente.

# PCA sobre correlações (equivalente a prcomp com scale.=TRUE)
pca <- prcomp(X, center = TRUE, scale. = TRUE)

pca %>% 
  summary()
Importance of components:
                         PC1    PC2    PC3    PC4     PC5     PC6     PC7
Standard deviation     1.726 1.4479 1.0389 0.8528 0.79846 0.73133 0.62458
Proportion of Variance 0.331 0.2329 0.1199 0.0808 0.07084 0.05943 0.04334
Cumulative Proportion  0.331 0.5640 0.6839 0.7647 0.83554 0.89497 0.93831
                           PC8     PC9
Standard deviation     0.55861 0.49310
Proportion of Variance 0.03467 0.02702
Cumulative Proportion  0.97298 1.00000

Os dois primeiros componentes capturam 56,4% da variância total, e os três primeiros chegam a 68,4%. Isso é um resultado muito típico em dados de marketing com vários atributos perceptuais: algumas dimensões latentes bem “macro” explicam boa parte da estrutura. Olhando os números, faz sentido reter duas componentes para construção do mapa perceptual (\(Y_1\) + \(Y_2\)), porque já carregam mais da metade da informação, e a \(Y_3\) adicionaria relativamente pouco ganho incremental (≈ +12%). Portanto, a representação bidimensional preserva a maior parte dos contrastes relevantes entre atributos e marcas, mantendo uma visualização simples e interpretável.

fviz_eig(pca, geom="line",  choice = c("eigenvalue"), addlabels = TRUE, main = "")

O scree plot mostra um “cotovelo” muito claro após o segundo componente: o autovalor cai de 3 → 2,1 → 1,1, e depois segue um declínio suave e quase linear. Esse formato clássico (queda acentuada nos dois primeiros PCs e cauda longa de autovalores pequenos) é um indicativo forte de que duas componentes já capturam a parte estrutural da variabilidade, enquanto as demais carregam essencialmente ruído/variação incomum. Em termos práticos de análise e comunicação gerencial, isso justifica a escolha de reduzir o espaço de 9 atributos para 2 dimensões para interpretar o mapa perceptual.

fa.parallel(X, fa="pc", n.iter=1000)

Parallel analysis suggests that the number of factors =  NA  and the number of components =  2 

A análise paralela confirma nossa escolha: apenas as duas primeiras componentes possuem autovalores claramente acima das linhas de referência do aleatório. A partir da terceira, os autovalores reais já ficam praticamente sobrepostos à distribuição simulada, indicando que o restante da variabilidade poderia ser explicado por ruído. Portanto, usando um critério mais robusto do que o scree visual, a conclusão é a mesma, ou seja, duas componentes são suficientes para capturar a estrutura latente relevante entre os 9 atributos avaliados.

3.1 Loadings, correlações e interpretação geométrica

Temos que as componentes encontradas são dadas por:

## Loadings (cargas)
pca$rotation
               PC1         PC2         PC3         PC4         PC5        PC6
perform  0.2374679  0.41991179  0.03854006 -0.52630873 -0.46793435  0.3370676
leader   0.2058257  0.52381901 -0.09512739 -0.08923461  0.29452974  0.2968860
latest  -0.3703806  0.20145317 -0.53273054  0.21410754 -0.10586676  0.1742059
fun     -0.2510601 -0.25037973 -0.41781346 -0.75063952  0.33149429 -0.1405367
serious  0.1597402  0.51047254 -0.04067075  0.09893394  0.55515540 -0.3924874
bargain  0.3991731 -0.21849698 -0.48989756  0.16734345  0.01257429  0.1393966
value    0.4474562 -0.18980822 -0.36924507  0.15118500  0.06327757  0.2195327
trendy  -0.3510292  0.31849032 -0.37090530  0.16764432 -0.36649697 -0.2658186
rebuy    0.4390184  0.01509832 -0.12461593 -0.13031231 -0.35568769 -0.6751400
                 PC7         PC8         PC9
perform -0.364179109 -0.14444718 -0.05223384
leader   0.613674301  0.28766118  0.17889453
latest   0.185480310 -0.64290436 -0.05750244
fun      0.007114761  0.07461259 -0.03153306
serious -0.445302862 -0.18354764 -0.09072231
bargain -0.288264900  0.05789194  0.64720849
value   -0.017163011  0.14829295 -0.72806108
trendy  -0.153572108  0.61450289 -0.05907022
rebuy    0.388656160 -0.20210688  0.01720236

\[Y_1 = 0,24 \times Z_{\text{perform}} + 0,21 \times Z_{\text{leader}} - 0,37 \times Z_{\text{latest}} - 0,25 \times Z_{\text{fun}} + 0,16 \times Z_{\text{serious}} + 0,40 \times Z_{\text{bargain}} + 0,45 \times Z_{\text{value}} - 0,35 \times Z_{\text{trendy}} + 0,44 \times Z_{\text{rebuy}}\]

e,

\[Y_2 = 0,42 \times Z_{\text{perform}} + 0,52 \times Z_{\text{leader}} + 0,20 \times Z_{\text{latest}} - 0,25 \times Z_{\text{fun}} + 0,51 \times Z_{\text{serious}} - 0,22 \times Z_{\text{bargain}} - 0,19 \times Z_{\text{value}} + 0,32 \times Z_{\text{trendy}} + 0,02 \times Z_{\text{rebuy}}\]

Observando as loadings, \(Y_1\) tem cargas altas positivas em value, bargain, rebuy e perform, indicando que esta dimensão parece sintetizar uma percepção geral de benefício percebido/custo-benefício/probabilidade de recompra (mais “valor concreto” da marca). Já \(Y_2\) tem cargas altas em leader, serious e perform, indicando que essa dimensão se aproxima mais de um eixo de prestígio/liderança/seriedade. Em síntese: \(Y_1\) capta “valor concreto oferecido”, \(Y_2\) capta “status institucional da marca”.

fviz_pca_biplot(pca, repel = TRUE,
                col.var = "#2E9FDF", # Variables color
                col.ind = "#696969"  # Individuals color
                )

No biplot com indivíduos, o padrão fica difícil de visualizar devido ao volume de pontos, sugerindo a execução da PCA usando avaliacoes agregadas por marca.

## Medias dos atributos por marca
brand.mean <- aggregate(. ~brand_fac, data = df_scaled, mean)
rownames(brand.mean) <- brand.mean[, 1]  # usar marca para os nomes das linhas
brand.mean <- brand.mean[, -1] # remover coluna de nome de marca
brand.mean
pca_mu <- prcomp(brand.mean, scale = TRUE)
pca_mu %>% 
  summary()
Importance of components:
                          PC1    PC2    PC3     PC4     PC5     PC6     PC7
Standard deviation     2.1345 1.7349 0.7690 0.61498 0.50983 0.36662 0.21506
Proportion of Variance 0.5062 0.3345 0.0657 0.04202 0.02888 0.01493 0.00514
Cumulative Proportion  0.5062 0.8407 0.9064 0.94842 0.97730 0.99223 0.99737
                           PC8     PC9
Standard deviation     0.14588 0.04867
Proportion of Variance 0.00236 0.00026
Cumulative Proportion  0.99974 1.00000

Realizada nova padronização, as médias agregadas têm escala um pouco diferente que os dados padronizados. A PCA neste contexto é extremamente dominante nas duas primeiras dimensões, isto é, \(Y_1\) sozinha já explica 50,6% da variância total, e \(Y_1 + Y_2\) explicam 84,1%. Ou seja, praticamente toda a estrutura relevante dos 9 atributos pode ser projetada com segurança em apenas duas dimensões.

fviz_pca_biplot(pca_mu, repel = TRUE,
                col.var = "#2E9FDF", # Variables color
                col.ind = "#696969"  # Individuals color
                )

Observamos aqui o mesmo agrupamento global de atributos e estrutura de associações. A Posição das variáveis nas componentes é consistente com ACP com todas as observações, de forma que podemos prosseguir com a interpretação do gráfico. No mapa perceptual, o eixo horizontal (\(Y_1 \approx 50,6\%\)) separa claramente marcas percebidas como mais “valor/custo-benefício/recompra” à direita (“f” e “g”) versus marcas com avaliações mais baixas nesses atributos à esquerda (“a”, “d”, “j”). Já o eixo vertical (\(Y_2 \approx 33,4\%\)) separa marcas mais “sérias/líderes/desempenho” na parte superior (“b” e “c”) versus marcas associadas a um perfil mais “divertido/jovem/informal” na parte inferior (“a” e “j”). Assim, as duas dimensões encontradas sintetizam de forma bem clara duas tensões estratégicas: valor concreto (\(Y_1\)) e prestígio vs. diversão (\(Y_2\)).

A marca “e” aparece exatamente próxima ao centro do mapa perceptual, sugerindo que ela não se destaca nem positivamente nem negativamente em nenhuma das duas dimensões principais. Em outras palavras, ela tende a ser percebida como “mediana” ou “neutra”, não é vista como uma marca particularmente moderna/divertida, nem como uma marca de alto prestígio/seriedade, e também não se posiciona como forte em valor/custo-benefício. Ela estaria, portanto, no espaço de “marca genérica”, ou seja, não agride, mas também não diferencia.

Isso pode ser bom ou ruim: há setores em que o consumidor valoriza o “não ter arestas”, ou seja, confiança, regularidade, estabilidade, não polêmica. Por exemplo, serviços financeiros conservadores, empresas B2B que vendem confiabilidade. Em um caso assim, estar no centro pode até ser seguro. Entretanto, se o jogo competitivo naquele setor depende de posicionamento claro (ex.: “premium”, “inovadora”, “low-cost”, “divertida”, etc.), então estar no centro é perigoso. A marca “e” pode estar sendo percebida como sem personalidade. Isso é típico de marcas que não conseguem defender um território mental.

Uma alternativa para a marca “e” seria, na prática, intervir nas percepções associadas à marca (por comunicação, experiência, produto ou preço) para que ela passe a ser percebida de forma mais alinhada a um território desejado, por exemplo, se o interesse é em realizar um deslocamento da marca “e” → “c” no espaço dos atributos padronizados:

## Diferenças entre a marca c e e
brand.mean["c",] - brand.mean["e",]

O vetor de diferença mostra que “c” é muito mais forte que e em serious (+1,18), perform (+1,21) e leader (+0,97). Estes são os atributos que definem o território de “c”: seriedade, liderança e desempenho. Por outro lado, “c” perde claramente em fun (−1,14), bargain (−1,16) e value (−0,86). Portanto, se a marca “e” quiser migrar na direção do território perceptual de “c”, ela precisa subir principalmente em seriedade, performance e liderança, uma vez que é exatamente aí que “c” se diferencia. Contudo, ela não deveria tentar deslocar ao mesmo tempo a sua eventual vantagem em diversão ou custo-benefício, pois “c” não compete nesses atributos.

Se o interesse é não seguir outra marca, mas obter espaço diferenciado, podemos deslocar nossa marca para áreas “vazias” no mapa. Agora estamos comparando a marca “e” a um cluster-alvo (“b”, “c”, “f”, “g”) que, pelo mapa, parece ser o cluster “das marcas vencedoras” em prestígio + valor concreto.

## Gap value-leader: Assumindo que o gap reflete aproximadamente a media dessas 4 marcas
colMeans(brand.mean[c("b", "c", "f", "g"), ]) - brand.mean["e", ]

Esse vetor gerado é o gap necessário para que a marca “e” se deslocasse em direção ao centro de gravidade das marcas de melhor desempenho perceptual. Para aproximar-se do “centro de massa” das marcas superiores (“b”,“c”,“f”,“g”), a marca “e” deveria priorizar aumento de desempenho (perform: +1,17), maior seriedade (serious: +0,57) e maior intenção de recompra (rebuy: +0,67). Além disso, reduzir ênfase em latest e fun.