スクリプトはこちら

1.データの読み込みおよび前処理

prst1 <- read.csv("https://goo.gl/z5P8ce") #データの読み込み
summary(prst1) #記述統計
##    Adaptable       BestValue      CuttingEdge     Delightful       Exciting    
##  Min.   :1.000   Min.   :1.000   Min.   :1.00   Min.   :1.000   Min.   :1.000  
##  1st Qu.:4.000   1st Qu.:3.000   1st Qu.:3.00   1st Qu.:3.000   1st Qu.:3.000  
##  Median :4.000   Median :4.000   Median :4.00   Median :4.000   Median :4.000  
##  Mean   :4.255   Mean   :3.849   Mean   :4.07   Mean   :3.983   Mean   :3.892  
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.00   3rd Qu.:5.000   3rd Qu.:5.000  
##  Max.   :7.000   Max.   :7.000   Max.   :7.00   Max.   :7.000   Max.   :7.000  
##     Friendly        Generous        Helpful        Intuitive    
##  Min.   :1.000   Min.   :1.000   Min.   :1.000   Min.   :1.000  
##  1st Qu.:4.000   1st Qu.:3.000   1st Qu.:3.000   1st Qu.:3.000  
##  Median :4.000   Median :4.000   Median :4.000   Median :4.000  
##  Mean   :4.246   Mean   :4.031   Mean   :3.894   Mean   :3.724  
##  3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:5.000   3rd Qu.:4.000  
##  Max.   :7.000   Max.   :7.000   Max.   :7.000   Max.   :7.000  
##     Brand          
##  Length:3050       
##  Class :character  
##  Mode  :character  
##                    
##                    
## 
str(prst1) #データの構造を確認
## 'data.frame':    3050 obs. of  10 variables:
##  $ Adaptable  : int  6 4 3 4 4 4 5 4 5 5 ...
##  $ BestValue  : int  5 3 2 1 1 3 3 2 4 3 ...
##  $ CuttingEdge: int  4 4 3 4 3 4 5 7 4 5 ...
##  $ Delightful : int  4 2 6 4 3 4 4 5 3 4 ...
##  $ Exciting   : int  3 4 5 5 3 3 6 4 3 5 ...
##  $ Friendly   : int  4 4 5 4 5 4 3 3 4 6 ...
##  $ Generous   : int  5 5 6 5 5 6 5 5 4 4 ...
##  $ Helpful    : int  4 2 4 3 4 2 3 4 3 5 ...
##  $ Intuitive  : int  3 5 3 3 4 4 4 4 3 5 ...
##  $ Brand      : chr  "Sierra" "Romeo" "Sierra" "Sierra" ...
sc <- prst1
sc[, 1:9] <- data.frame(scale(prst1[, 1:9])) #1~9列目を標準化
summary(sc)
##    Adaptable         BestValue        CuttingEdge         Delightful      
##  Min.   :-3.3414   Min.   :-2.7323   Min.   :-2.88159   Min.   :-3.04151  
##  1st Qu.:-0.2622   1st Qu.:-0.8139   1st Qu.:-1.00463   1st Qu.:-1.00202  
##  Median :-0.2622   Median : 0.1453   Median :-0.06616   Median : 0.01772  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000   Mean   : 0.00000  
##  3rd Qu.: 0.7643   3rd Qu.: 1.1045   3rd Qu.: 0.87232   3rd Qu.: 1.03746  
##  Max.   : 2.8171   Max.   : 3.0228   Max.   : 2.74928   Max.   : 3.07695  
##     Exciting          Friendly          Generous           Helpful        
##  Min.   :-2.8785   Min.   :-3.2141   Min.   :-3.20078   Min.   :-2.67745  
##  1st Qu.:-0.8881   1st Qu.:-0.2435   1st Qu.:-1.08908   1st Qu.:-0.82696  
##  Median : 0.1070   Median :-0.2435   Median :-0.03323   Median : 0.09829  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000   Mean   : 0.00000  
##  3rd Qu.: 1.1022   3rd Qu.: 0.7467   3rd Qu.: 1.02262   3rd Qu.: 1.02353  
##  Max.   : 3.0925   Max.   : 2.7271   Max.   : 3.13431   Max.   : 2.87403  
##    Intuitive          Brand          
##  Min.   :-2.8282   Length:3050       
##  1st Qu.:-0.7519   Class :character  
##  Median : 0.2863   Mode  :character  
##  Mean   : 0.0000                     
##  3rd Qu.: 0.2863                     
##  Max.   : 3.4007

2.相関行列を可視化

library(corrplot)
## corrplot 0.95 loaded
corrplot(cor(sc[, 1:9]), 
         order = "hclust") #似た変数同士をまとめて表示

 9つの属性が3つのグループに分類される。以降、これらをそれぞれ感情系(Generous, Delightful, CuttingEdge, Exciting)、実用系(Adaptable, BestValue)、使いやすさ系(Helpful, Friendly, Intuitive)とする。

3.ヒートマップ

library(gplots)
## Warning: package 'gplots' was built under R version 4.5.3
## 
## ---------------------
## gplots 3.3.0 loaded:
##   * Use citation('gplots') for citation info.
##   * Homepage: https://talgalili.github.io/gplots/
##   * Report issues: https://github.com/talgalili/gplots/issues
##   * Ask questions: https://stackoverflow.com/questions/tagged/gplots
##   * Suppress this message with: suppressPackageStartupMessages(library(gplots))
## ---------------------
## 
## Attaching package: 'gplots'
## The following object is masked from 'package:stats':
## 
##     lowess
library(RColorBrewer)

prst1.mean <- aggregate(. ~ Brand, data = sc,
                        mean) #ブランドごとに平均を算出
prst1.mean.matrix <- as.matrix(prst1.mean[, -1]) #1列目を除いて行列変換

rownames(prst1.mean.matrix) <- prst1.mean[, 1] #1列目のブランドを行名に
heatmap.2(prst1.mean.matrix, #ヒートマップは行列を受け取る
          col=brewer.pal(9, "GnBu"), #緑から青への9段階で表現
          trace="none", #トレースラインは非表示
          key=TRUE, #色と数値の対応を表示
          dend="none", #樹形図の非表示
          main="\n\n\nBrand attributes") #/nは改行

 この図は属性スコアの平均をブランドごとに表示したものである。濃い青が高評価、薄い緑は低評価を意味し、9つのグラデーションを設けている。感情系(Generous, Delightful, CuttingEdge, Exciting)ではTango・Sierra、使いやすさ系(Helpful, Friendly, Intuitive)ではRomeo・Papaが高評価を得ているとが分かる。

4.主成分分析

prst.pc <- prcomp(sc[, 1:9]) #1~9列目を指定して分析
summary(prst.pc)
## Importance of components:
##                           PC1    PC2    PC3     PC4     PC5     PC6     PC7
## Standard deviation     1.3990 1.3577 1.1115 0.91215 0.84742 0.83450 0.77850
## Proportion of Variance 0.2175 0.2048 0.1373 0.09245 0.07979 0.07738 0.06734
## Cumulative Proportion  0.2175 0.4223 0.5595 0.65200 0.73179 0.80917 0.87651
##                            PC8     PC9
## Standard deviation     0.76278 0.72774
## Proportion of Variance 0.06465 0.05885
## Cumulative Proportion  0.94115 1.00000
plot(prst.pc, type="l") #折れ線グラフで固有値をプロット

 主成分とは複数の変数をまとめた新しい指標を指す。主成分分析とは、説明変数を要約する手法で、情報量をできる限り減らさず、次元(変数の数)を減らすことが目的である。今回の場合だと、9つの属性を2次元に圧縮し、ブランドの立ち位置を可視化していく。固有値とは各主成分が持つばらつきの大きさを指し、主成分が持つ情報量の指標である。

5.PC1 vs PC2のバイプロット

rownames(prst1.mean) <- prst1.mean[, 1] #ブランド名を行名に
prst.mu.pc <- prcomp(prst1.mean[, -1], scale = TRUE) #1列除いて主成分分析
biplot(prst.mu.pc,
       main = "Brand positioning", #タイトル
       cex  = c(1.0, 0.7), #文字の大きさ
       col  = c("black", "blue"), #色の指定
       xlim = c(-0.8, 0.8), #軸の調整
       ylim = c(-0.8, 0.8)
       ) #expandで矢印の長さを変えられる

 軸は2つの主成分、左下のメモリは主成分スコア、右上のメモリは主成分負荷量、青い矢印と文字は属性と対応する主成分負荷量を指す。主成分スコアとは属性評価を主成分負荷量で重みづけて合計したものである。PC1の軸から見ると、0.0を中心に右側の属性(主に感情系)と正の関係、左側の属性(使いやすさ系)とは負の関係であることを示す。

 PC2の軸から見ると、どの属性も0.0付近に集中しており、負荷量の絶対値が低い。しかし、実用系(Adaptable, BestValue)の負荷量が高く、PC2にそれらの変数が強い影響を及ぼしていることが分かる。

 各ブランドを主成分スコアで見ると、いずれも0.0付近に集中しており、ブランド間の差が微々たるものであると読み取れる。PC1を軸にしてSierraを見ると、属性評価を主成分負荷量で重みづけした合計は正の値を取った。つまり、負荷量の絶対値に大きな差が見られないため、属性評価で感情系の評価が使いやすさ系を上回っていたことが推論される。

 ところが、負荷量の絶対値にばらつきがある場合、特定の属性が主成分スコアを支配する。よって、負荷量の絶対値が大きい属性を重点的に強化していけば、主成分スコアは大きく変わる。つまり、プロット上で大きく座標が変わり、空白領域への移動や他社ブランドと距離をとることで、差別化につながる。

6.主成分負荷量の確認

prst.mu.pc$rotation[, 1:2]
##                    PC1          PC2
## Adaptable   -0.3249726  0.666519230
## BestValue    0.3235628  0.709203551
## CuttingEdge  0.3366189 -0.002848791
## Delightful   0.3340600  0.026823293
## Exciting     0.3365956  0.031687364
## Friendly    -0.3360906  0.136248881
## Generous     0.3359019  0.130004276
## Helpful     -0.3357895  0.120451765
## Intuitive   -0.3360855 -0.032821482

 主成分負荷量は各変数が主成分にどれだけ影響を及ぼしているを示す。scale = TRUEは変数を標準化してからPCAを行う設定で、単位や分散の大きさが異なる変数を同じ基準で比較できる。このとき負荷量は相関係数と同じ感覚で読める。正の値が大きいほどその主成分と同じ方向、負の値が大きいほど逆方向の関係を示す。

7.ブランド間の属性差を確認

prst1.mean["Papa", -1] - prst1.mean["Romeo", -1]
##       Adaptable  BestValue CuttingEdge Delightful   Exciting  Friendly
## Papa 0.09844577 -0.1019352  -0.4119292 -0.4100553 -0.3808321 0.3096705
##        Generous   Helpful Intuitive
## Papa -0.1970958 0.3474463 0.3182752
colMeans(prst1.mean[c("Papa","Romeo"),-1]) - prst1.mean["Papa",-1]
##        Adaptable  BestValue CuttingEdge Delightful  Exciting   Friendly
## Papa -0.04922289 0.05096758   0.2059646  0.2050277 0.1904161 -0.1548352
##        Generous    Helpful  Intuitive
## Papa 0.09854789 -0.1737231 -0.1591376
colMeans(prst1.mean[c("Papa","Sierra"),-1]) - prst1.mean["Papa",-1]
##       Adaptable  BestValue CuttingEdge Delightful  Exciting   Friendly
## Papa -0.1167683 0.07875469   0.3905468  0.2953398 0.3491926 -0.3143105
##       Generous   Helpful  Intuitive
## Papa 0.1981832 -0.298416 -0.3408995

 1行目では、PapaとRomeoにおける平均属性評価の差を取っている。主に使いやすさ系(Helpful, Friendly, Intuitive)ではPapa、感情系(Generous, Delightful, CuttingEdge, Exciting)ではRomeoが相対的に高い評価を得ている。しかし、実用系は分かれており、AdaptableではPapa、BestValueではRomeoが高い評価を得ている。

 2・3行目ではPapaと競合ブランドの中間点を算出している。これはバイプロット上の空白領域、つまり既存ブランドが占めていないポジションを狙う際に、どの属性をどれだけ強化・抑制すればいいかを定量的に把握するためのものである。正の値が大きい属性は、競合と比較したときのPapaの弱点であり、強化の余地があることを示す。  

8.PC2 vs PC3のバイプロット

biplot(prst.mu.pc,
       choices = c(2,3),
       main    = "Brand positioning PC2 vs PC3",
       cex     = c(1,0.7),
       xlim    = c(-0.9,0.9),
       ylim    = c(-0.9,0.9))

prst.mu.pc$rotation[,2:3]
##                      PC2         PC3
## Adaptable    0.666519230  0.22792759
## BestValue    0.709203551 -0.14732265
## CuttingEdge -0.002848791 -0.03520907
## Delightful   0.026823293  0.77806121
## Exciting     0.031687364  0.02819116
## Friendly     0.136248881  0.12350429
## Generous     0.130004276 -0.26500833
## Helpful      0.120451765 -0.33383561
## Intuitive   -0.032821482  0.34928849

 PC2を軸に主成分負荷量を見ていくと、実用系(Adaptable, BestValue)が高く、これはPapaやTangoにとってさらなる強みとして訴求できるチャンスである。Romeoは突出した評価がなく、印象を創れる可能性がある。Sierraは実用系との関連が低いと主成分スコアから推論され、Adaptable, BestValueで差別化しようとすると、商品と顧客の持つイメージとの乖離が懸念される。しかし、負の主成分負荷量は少ないため、負の方向での差別化は現状厳しいと言える。

 PC3を軸に主成分負荷量を見ていくと、Delightfulが突出して高く、これはRomeoにとって強みとして訴求できるチャンスである。SierraとTangoは中立であり、Delightful方向への展開の余地がある。しかし、SierraはPC2を軸に見ると、明確なアピールポイントを持ちにくい状況のため、PC3におけるDelightful方向への展開が現実的な差別化の選択肢であると考えられる。

9.まとめ

 本分析では、ブランドポジショニングを主成分分析とバイプロットを用いて可視化した。PC1では感情系(Generous, Delightful, CuttingEdge, Exciting)と使いやすさ系(Helpful, Friendly, Intuitive)の対立軸が確認され、PC2では実用系(Adaptable, BestValue)、PC3ではDelightfulが主要な差別化軸として示された。PapaやTangoは実用系での訴求余地、RomeoはDelightfulでの強化が現実的な選択肢として挙げられる。SierraはPC1・PC2において明確なポジションを築きにくいが、PC3ではDelightful方向へのシフトが現実的な差別化戦略であると考えられる。