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" ...
prst.sc <- prst1
prst.sc[, 1:9] <- data.frame(scale(prst1[, 1:9])) #1から9列目を標準化
summary(prst.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
library(nFactors)
## Warning: package 'nFactors' was built under R version 4.5.3
ns <- nScree(prst.sc[, 1:9]) #スクリーテスト
plotnScree(ns) #可視化
eigen(cor(prst.sc[, 1:9])) #固有値と固有ベクトルを表示
## eigen() decomposition
## $values
## [1] 1.9573315 1.8432173 1.2354099 0.8320148 0.7181264 0.6963876 0.6060699
## [8] 0.5818321 0.5296106
##
## $vectors
## [,1] [,2] [,3] [,4] [,5]
## [1,] -0.454796056 0.018771390 0.484854547 -0.022290444 -0.001595812
## [2,] -0.200424840 0.022560279 0.758421452 -0.036874375 -0.040645411
## [3,] -0.004346220 -0.550602529 0.049599530 0.140771690 0.328512346
## [4,] -0.008382854 -0.493143304 -0.006078214 0.284618447 -0.816903535
## [5,] -0.015746816 -0.532195521 0.026882143 0.283250965 0.465175395
## [6,] -0.488578311 0.007292388 -0.259651422 -0.037444609 0.028633300
## [7,] -0.004171407 -0.411362484 -0.034895270 -0.901283819 -0.062223349
## [8,] -0.482335720 0.012399852 -0.233318665 0.002813413 0.026111045
## [9,] -0.530357797 -0.011274003 -0.251831534 0.058012424 -0.036498109
## [,6] [,7] [,8] [,9]
## [1,] 0.049382497 -0.18545094 0.32478016 0.64413664
## [2,] -0.019143658 0.13485725 -0.28416622 -0.53085088
## [3,] -0.187618684 0.70577873 0.04259771 0.17743129
## [4,] 0.016784507 -0.06080094 -0.05827660 0.03144492
## [5,] 0.167478871 -0.60095192 -0.04878140 -0.16615068
## [6,] 0.626816396 0.18494971 -0.50286566 0.10778763
## [7,] 0.003136973 -0.10013813 0.03733792 -0.04393123
## [8,] -0.733596722 -0.17012473 -0.37927746 0.03336511
## [9,] 0.050896382 0.10621403 0.63879392 -0.47806620
factanal(prst.sc[, 1:9], factor=2)
##
## Call:
## factanal(x = prst.sc[, 1:9], factors = 2)
##
## Uniquenesses:
## Adaptable BestValue CuttingEdge Delightful Exciting Friendly
## 0.829 0.988 0.581 0.751 0.645 0.674
## Generous Helpful Intuitive
## 0.859 0.698 0.526
##
## Loadings:
## Factor1 Factor2
## Adaptable 0.414
## BestValue 0.111
## CuttingEdge 0.647
## Delightful 0.498
## Exciting 0.596
## Friendly 0.571
## Generous 0.376
## Helpful 0.550
## Intuitive 0.687
##
## Factor1 Factor2
## SS loadings 1.286 1.164
## Proportion Var 0.143 0.129
## Cumulative Var 0.143 0.272
##
## Test of the hypothesis that 2 factors are sufficient.
## The chi square statistic is 523.11 on 19 degrees of freedom.
## The p-value is 7.84e-99
factanal(prst.sc[, 1:9], factor=3)
##
## Call:
## factanal(x = prst.sc[, 1:9], factors = 3)
##
## Uniquenesses:
## Adaptable BestValue CuttingEdge Delightful Exciting Friendly
## 0.706 0.005 0.579 0.752 0.646 0.671
## Generous Helpful Intuitive
## 0.859 0.699 0.506
##
## Loadings:
## Factor1 Factor2 Factor3
## Adaptable 0.372 0.394
## BestValue 0.997
## CuttingEdge 0.648
## Delightful 0.498
## Exciting 0.595
## Friendly 0.573
## Generous 0.376
## Helpful 0.548
## Intuitive 0.702
##
## Factor1 Factor2 Factor3
## SS loadings 1.262 1.164 1.152
## Proportion Var 0.140 0.129 0.128
## Cumulative Var 0.140 0.270 0.398
##
## Test of the hypothesis that 3 factors are sufficient.
## The chi square statistic is 11.99 on 12 degrees of freedom.
## The p-value is 0.446
探索的因子分析とは、観測された複数の変数に隠れ潜む共通の概念を発見する手法である。因子とは複数の変数に対して影響を与えている潜在的な概念を指す。例えば、「語彙力」「読解力」「文章力」の3変数が共通して高いという結果には、背後に「言語能力」という因子があると考えられる。換言すると、実証的に観察できるもの(顕在変数)ではないが、複数の変数を通して明らかになるもの(潜在変数)である。
固有値とは、ある因子が観測変数全体における分散を、どの程度説明するかを示す指標である。例えば、固有値 = 2.0 だとその因子は2変数分のばらつきを説明していると解釈する。また、因子の採用には固有値1以上の基準を設ける(Kaiser基準)。スクリーテストとは、固有値を大きい順に並べた際、固有値の減少が急から緩やかに変化する点の直前までを因子数とする手続きであり、今回は3因子を採用する。
factanal()は因子分析を行う関数であり、factor=kで因子数を指定できる。Uniquenesses(独自性)はその変数の分散のうち、因子で説明できなかった部分である。例えば、Adaptableが0.829なら、1 - Uniqueness(0.829) = 0.171(17%)は因子で説明できた割合となる。Loadings(因子負荷量)は厳密には変数と因子の共分散なのだが、factanal()は変数を標準化してから計算するため、結果として相関係数と一致する。また、0に近い因子負荷量は表示されない。それを踏まえて、どの変数がどの因子にどれだけ強く結びついているかを確認する。
SS loadingsは各変数における負荷量の二乗和であり、その因子がどれくらい分散を説明するかを示す。因子数を2に指定したときの出力だと、Factor1のSS loadingsが1.286なら、9変数のばらつきのうち1.286個分説明していると読む。Proportion Varは全変数のうち、その因子が説明する割合である。SS loadingsが1.286の例だと、Factor1は0.140(14.3%)ほど説明していると読む。SS loadingsは個数単位で、Proportion Varは割合で示しているところに注意されたい。Cumulative Varはそれまでの因子における分散の説明割合を足し合わせたものである。Factor2のCumulative Varだと、Factor1(0.140)とFactor2(0.129)のProportion Varを足し合わせて四捨五入したものが0.270と出力されている。
P値の解釈について、Factor=2だと7.84e-99(ほぼ0)であり、Factor=3だと0.446(44.6%)である。検定では「P値が小さい=有意な差がある」という解釈になることが多いが、因子分析における帰無仮説は「この因子数でデータを十分に説明できている」となる。つまり、データとモデルに有意な差があると、それは因子モデルが変数間の関係を再現できてないことになる。その場合はモデルの再現性を上げるため、因子数を増やす必要がある。
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)
brand.fa <- factanal(prst.sc[, 1:9], factor=3)
heatmap.2(brand.fa$loadings,
col = brewer.pal(9, "Greens"), #色を緑の9段階の濃淡で表示
trace = "none", #トレースラインの非表示(デフォだと表示)
key = TRUE, #色の凡例を表示
dend = "none", #樹形図の非表示
Colv = FALSE, #因子列の並び替えなし
cexCol = 1.2, #列ラベルのフォントを1.2倍大きく
main = "\n\n\n Factor loadings for brand adjective"
#タイトルを\nで改行しながら表示
)
library(semPlot)
## Warning: package 'semPlot' was built under R version 4.5.3
semPaths(brand.fa,
what = "est", #推定値(因子負荷量)を表示
residuals = FALSE, #残差(独自性)は非表示
cut = 0.3, #0.3以下の負荷量は薄く表示
posCol = c("white","darkgreen"), #正の負荷量は白から濃い緑のグラデーションで表現
negCol = c("white","red"), #負の負荷量は白から赤のグラデーションで表現
edge.label.cex = 0.75, #数値ラベルのフォントサイズ指定
nCharNodes = 7 #各変数の表示文字数を制限
)
brand.fa2 <- factanal(prst.sc[,1:9],
factors = 3,
scores = "Bartlett" #Bartlett法で算出
)
brand.score <- data.frame(brand.fa2$scores) #得点を取り出してdfに
brand.score$brand <- prst.sc$Brand #ブランド名を追加
head(brand.score) #先頭表示
## Factor1 Factor2 Factor3 brand
## 1 -0.2533476 -0.26787615 1.1022112 Sierra
## 2 0.1653136 -0.44532362 -0.8175906 Romeo
## 3 -0.2232188 1.21523387 -1.7712950 Sierra
## 4 -0.5896332 0.80274750 -2.7424697 Sierra
## 5 0.8532805 -1.20936245 -2.7323045 Sierra
## 6 -0.5192238 0.04341744 -0.8279926 Sierra
fa.mean <- aggregate(. ~ brand, data = brand.score, mean) #ブランドごとに平均を算出
rownames(fa.mean) <- fa.mean[, 1] #1列目のブランド名を行名に
fa.mean <- fa.mean[, -1] #1列除いて代入
names(fa.mean) <- c("Friend","Edge","Value") #ラベルをつける
fa.mean
## Friend Edge Value
## Papa 0.7175496 -0.8622579 -0.12711879
## Romeo 0.2073764 -0.2006271 -0.02943947
## Sierra -0.3025375 0.3144044 0.02001072
## Tango -0.7420775 0.8851260 0.22597196
heatmap.2(as.matrix(fa.mean), #ヒートマップ
col = brewer.pal(9,"GnBu"),
trace = "none",
key = TRUE,
dend = "none",
cexCol = 1.2,
main = "\n\n Mean factor score by brand"
)
因子得点とは、各観測対象が各因子をどれだけ反映しているかを示す値である。因子得点は標準化されていることと、最初の出力は1行が1回答者のブランドに対する評価であることに留意されたい。出力からブランドは親しみやすさ系と革新系に分かれていることが読み取れる。そして、Friend因子とEdge因子はトレードオフの関係にある。つまり、親しみやすいブランドは革新性を評価されず、革新性が高いブランドは親しみにくい。Value因子は中間的な位置にあり、2つの因子と強い結びつきが見られない。そのため、トレードオフを考慮したうえで、コスパに焦点を挙げていくことが有効である。