【R】因子分析
1.はじめに
あるデータをモデル化するときに、変数の数があまりに多い場合や変数の中に相互に相関の高いものが混じっている場合には、変数の数を減らす(次元を削減)する必要があります。このための手段としては、いくつかありますが、その一つが因子分析です。因子分析では、共通項をくくりだすことができます。
2.データ
ここでは、Rに含まれるmtcars
というデータを使用します。Rのドキュメントによると、Motor Trendという1974年のアメリカの車雑誌から、下記の11の変数に対して1973-1974年に発売された32種の車のデータを記載したものらしいです。
[, 1] mpg Miles/(US) gallon
[, 2] cyl Number of cylinders
[, 3] disp Displacement (cu.in.)
[, 4] hp Gross horsepower
[, 5] drat Rear axle ratio
[, 6] wt Weight (1000 lbs)
[, 7] qsec 1/4 mile time
[, 8] vs Engine (0 = V-shaped, 1 = straight)
[, 9] am Transmission (0 = automatic, 1 = manual)
[,10] gear Number of forward gears
データの前半部分はこのようになっています。
> head(mtcars)
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
3.因子数の決定
抽出する因子数を決定する方法の一つにスクリープロットの利用があります。これは、相関行列からその固有値を求めプロットします。固有値が1より小さくなる直前までを共通因子として採用するものです。
library(tidyverse) library(psych) library(ggplot2) result.prl<-fa.parallel(mtcars, fm="ml")
自分で相関行列をcor
により求め、eigen(cor)$values
から固有値を求め、それをplot
しても良いのですが、psych
パッケージにfa.parallel
という関数があるのでこれを利用しました。実行結果は下記の通りです。この結果より、固有値が1以上であることから、因子数を2と決定します。
4.因子分析
因子分析は、factanal
関数でできます。因子数2ですので、factor=2
とします。また、回転はバリマックス回転とします。
ret<-factanal(mtcars, factors = 2, rotation = "varimax") print(ret, digit=3, cut=0, sort=TRUE)
Call:
factanal(x = mtcars, factors = 2, rotation = "varimax")
Uniquenesses:
mpg cyl disp hp drat wt qsec vs am gear carb
0.167 0.070 0.096 0.143 0.298 0.168 0.150 0.256 0.171 0.246 0.386
Loadings:
Factor1 Factor2
mpg 0.686 -0.602
disp -0.730 0.609
drat 0.807 -0.225
wt -0.810 0.420
am 0.907 0.081
gear 0.860 0.125
cyl -0.629 0.731
hp -0.337 0.862
qsec -0.162 -0.908
vs 0.291 -0.812
carb 0.031 0.783
Factor1 Factor2
SS loadings 4.494 4.357
Proportion Var 0.409 0.396
Cumulative Var 0.409 0.805
Test of the hypothesis that 2 factors are sufficient.
The chi square statistic is 68.57 on 34 degrees of freedom.
The p-value is 0.000405
このような結果になりました。
- uniquenesses(独自因子の分散)
- Loadings(因子負荷量)
観測変数に対して共通因子がどの程度影響を与えているか。 - SS loadings(因子寄与):各因子の2乗和
- Proportion Var(因子寄与率):因子寄与/項目数
その因子が全体分散のうちどの程度の割合を説明しているか。 - Cumulative Var(累積寄与率):因子寄与率を大きい順に積算。
因子1Factor1
>因子2Factor2
となる[mpg, disp, drat, wt, am, gear]の組と、逆の[cyl, hp, qsec, vs, carb]に分けられそうです。この意味付けをすることが人間の役割ですが・・・。さて、それぞれの因子は何を表すのでしょうか?思いつきませんでした・・・。Cumulative Var
より80.5%の説明ができているようです。この結果をグラフにしてみるとよりよくわかりそうです。
tf<-ret$loadings[c(1:11),c(1:2)] %>% as_tibble() tf <- data.frame(c(colnames(mtcars)), tf[,1]^2, tf[,2]^2, 1-tf[,1]^2-tf[,2]^2) colnames(tf)<-c("Spec", "Factor1", "Factor2", "Other") tf_long<-tf %>% tibble::rowid_to_column("id") %>% pivot_longer(c(-id, -Spec), names_to = "f_name", values_to = "val") ggplot(tf_long, aes(x=Spec, y=val, fill=f_name))+ geom_bar(stat = "identity", position = "fill") + labs(fill="Factor") + coord_flip()
寄与率を円グラフにしてみます。どのFactorがどれだけ寄与しているかわかります。
# calculate the proportion var of "other" fu<-unlist(ret) # Calculate the proportion Variance of Fator1 prop_var1<-sum(ret$loadings[,1]^2)/nrow(ret$loadings) # Calculate the proportion Variance of Fator2 prop_var2<-sum(ret$loadings[,2]^2)/nrow(ret$loadings) # calculate the proportion var of "other" prop_var_other<-1-prop_var1-prop_var2 prop_var<-data.frame("F_name"=c("Factor1", "Factor2", "Other"), "Val"=c(prop_var1, prop_var2, prop_var_other)) prop_var$label <- scales::percent(prop_var$Val) ggplot(prop_var, aes(x="", y=Val, fill=F_name)) + geom_bar(stat="identity", width = 1)+ coord_polar("y", start=0, direction = -1)+ theme_void() + labs( fill = "Factor") + geom_text(aes(x=1, y = rev(cumsum(Val)-Val/1.3) , label=label))
5.結果まとめ
- スクリープロットより因子数は2
- 第一因子は
[mpg, disp, drat, wt, am, gear]
が高い因子負荷量を示した。ており、第二因子は[cyl, hp, qsec, vs, carb]
が高い因子負荷量を示した。意味の解釈まではできず・・・。 - 2因子で全体の分散の80.5%を説明できている。