『入門・社会統計学――2ステップで基礎から〔Rで〕学ぶ』

第11章 主成分分析と因子分析

Author

SUGINO Isamu, Build with R4.5.2

Published

March 1, 2026

0 全体の章構成

1 主成分分析(Principal Component Analysis)

 主成分分析(PCA; Principal Component Analysis)のモデルを図示すると以下の様になる。観測された変数を元に,主成分得点を合成するのである。
 調査で実際に回答などの形で情報(数値)を得られている観測変数を var1 などと表記し,□で表す。それに対して,主成分(principal component)や因子(factor)など,直接観測されていない潜在変数を○で表す。

DiagrammeRによるPCA作図
grViz("
digraph PCA {
  graph [label = <<I>Principal Component Analysis</I>>, labelloc = t ];
  var1[shape=box, label = <var&#8321;>];
  var2[shape=box, label = <var&#8322;>];
  var3[shape=box, label = <var&#8323;>];
  var4[shape=box, label = <var&#8324;>];
  var5[shape=box, label = <var&#8325;>];
  var6[shape=box, label = <var&#8326;>];
  pc1[label = <principal component&#8321;>];
  pc2[label = <principal component&#8322;>];
  var1 -> pc1;
  var2 -> pc1;
  var3 -> pc1;
  var4 -> pc1;
  var5 -> pc1;
  var6 -> pc1;
  var1 -> pc2;
  var2 -> pc2;
  var3 -> pc2;
  var4 -> pc2;
  var5 -> pc2;
  var6 -> pc2;
}")

1-1 データが有する情報量の次元の縮約

3つの 主成分を合成するモデル

\[PC_{1}=h_{11}x_{1}+h_{12}x_{2}+...+h_{1j}x_{j}+...+h_{1p}x_{p}\] \[PC_{2}=h_{21}x_{1}+h_{22}x_{2}+...+h_{2j}x_{j}+...+h_{2p}x_{p}\] \[PC_{3}=h_{31}x_{1}+h_{32}x_{2}+...+h_{3j}x_{j}+...+h_{3p}x_{p}\]  データフレイム名はd01とする。
 まずは使用する変数の度数分布から,欠損値処理が必要かどうかを確認し,必要なものは処理をする1
 また,頻度が高い方が数値が大きくなるよう,必要があれば変換する。

d01 <- read.csv("practice.csv")

調査票の確認

with(d01, table(q0101, useNA = "always")) # 1~4
q0101
   1    2    3    4 <NA> 
  98  168   85   32    1 
with(d01, table(q0102, useNA = "always")) # 1~5
q0102
   1    2    3    4    5 <NA> 
  93    6    8   19  257    1 
with(d01, table(q0103, useNA = "always")) # 1~8
q0103
   1    2    3    4    5    6    7    8    9 <NA> 
  76   14    5   19    8   19  147   93    2    1 
with(d01, table(q0200, useNA = "always")) # 1~6
q0200
   1    2    3    4    5    6    7 <NA> 
  73   64  135   49   37   24    1    1 
with(d01, table(q0301, useNA = "always")) # 1~5
q0301
   1    2    3    4    5 <NA> 
  13   64   83   45  179    0 
with(d01, table(q0302, useNA = "always")) # 1~5
q0302
   1    2    3    4    5 <NA> 
  67   65   61   47  142    2 
with(d01, table(q0401, useNA = "always")) # 1~5
q0401
   1    2    3    4    5 <NA> 
 104   44   41   14  179    2 
with(d01, table(q0402, useNA = "always")) # 1~5
q0402
   1    2    3    4    5 <NA> 
   9   15   38   40  281    1 
with(d01, table(q0403, useNA = "always")) # 1~7
q0403
   1    2    3    4    5    6    7 <NA> 
 291    5    9   19   47   10    2    1 

値が大きい方がその活動を活発に行っている事を意味する様に新変数を作成する(同時に欠損値処理を行う)。

# 欠損値処理と値の逆転
d01$NetShop   <- c(1:4)[d01$q0101]
d01$Devices   <- c(1:5)[d01$q0102]
d01$SNS       <- c(8:1)[d01$q0103]
d01$Books     <- c(1:6)[d01$q0200]
d01$Library   <- c(5:1)[d01$q0301]
d01$Comics    <- c(5:1)[d01$q0302]
d01$NewsPaper <- c(1:5)[d01$q0401]
d01$Volunteer <- c(5:1)[d01$q0402]
d01$Smoking   <- c(1:7)[d01$q0403]
Tip完備ケースデータフレイムの作成

 次に,完備ケース分析用にケース選択し,使用する変数だけに限定したデータフレイムd11を作成する2

full.11 <- with(d01, 
                complete.cases(NetShop, Devices, SNS, Books, Library, 
                               Comics, NewsPaper, Volunteer, Smoking))

d11 <- d01[full.11, c("NetShop", "Devices", "SNS", "Books", "Library", 
                      "Comics", "NewsPaper", "Volunteer", "Smoking")]

この様に準備しておけば主成分分析は簡単に出来る。prcomp( )

(pr1 <- prcomp(d11, scale = T)) # 主成分分析を実行して同時に結果を表示
Standard deviations (1, .., p=9):
[1] 1.3480341 1.2762922 1.0299375 0.9838979 0.9363329 0.8974959 0.8434077
[8] 0.7614977 0.7427129

Rotation (n x k) = (9 x 9):
                  PC1         PC2         PC3         PC4         PC5
NetShop    0.49802484 -0.05594720 -0.04395227  0.24386147 -0.10064407
Devices    0.55462152 -0.11620220  0.06292039  0.13546901 -0.04559114
SNS        0.51380170 -0.14901883  0.37208178 -0.02327602 -0.09483285
Books      0.19839061  0.50629241 -0.12871992 -0.15505025 -0.37457317
Library    0.15476394  0.45689311 -0.30059386 -0.17007928  0.44947710
Comics     0.25179900 -0.09923688 -0.72421757 -0.28591804 -0.14384478
NewsPaper -0.14936189  0.45042646  0.10294634  0.20288696 -0.64220223
Volunteer  0.15650630  0.37518387  0.45674402 -0.52435071  0.24006680
Smoking   -0.08280943 -0.37760050  0.07095590 -0.68615925 -0.38172915
                  PC6         PC7           PC8         PC9
NetShop    0.60884535  0.01426529 -0.5295311033  0.16128354
Devices   -0.33674794  0.18406205  0.0005812592 -0.71219681
SNS       -0.19862640  0.09917056  0.4259953369  0.57884543
Books      0.35694017 -0.34882468  0.4825835005 -0.20352623
Library    0.09155721  0.64768373  0.1063191634  0.08247915
Comics    -0.39301714 -0.24408349 -0.1866299324  0.22571622
NewsPaper -0.30941826  0.33870309 -0.2873705693  0.13259326
Volunteer -0.16487432 -0.30042330 -0.4194222320 -0.01411737
Smoking    0.25155723  0.38776191 -0.0246223850 -0.12143918

scale = Tというオプションは元の変数を標準化するというオプションである3
prcomp( ) 関数のデフォルトはscale = Fであり,明示的に指定しないと標準化されない。
標準化をしないと元の変数の単位や散布度の違いによって結果が影響される。
元の変数の散布度の違いも重要であるならばそれでも良いが,ここでの分析例のようにそもそも単位がまったく違ったり散布度の違いが重要でない場合は,明示的にscale = Tとすることが必要である4

主成分分析の結果に含まれる情報名を確認

names(pr1)
[1] "sdev"     "rotation" "center"   "scale"    "x"       

標準偏差を二乗して分散(=固有値)を求める。

pr1$sdev^2 
[1] 1.8171959 1.6289217 1.0607713 0.9680552 0.8767194 0.8054988 0.7113366
[8] 0.5798788 0.5516225

元のデータで,相関係数行列を固有値分解すると,主成分分析の結果と(符号が反転する事はあるが)一致する。

eigen(cor(d11))
eigen() decomposition
$values
[1] 1.8171959 1.6289217 1.0607713 0.9680552 0.8767194 0.8054988 0.7113366
[8] 0.5798788 0.5516225

$vectors
             [,1]        [,2]        [,3]        [,4]        [,5]        [,6]
 [1,] -0.49802484  0.05594720  0.04395227 -0.24386147  0.10064407  0.60884535
 [2,] -0.55462152  0.11620220 -0.06292039 -0.13546901  0.04559114 -0.33674794
 [3,] -0.51380170  0.14901883 -0.37208178  0.02327602  0.09483285 -0.19862640
 [4,] -0.19839061 -0.50629241  0.12871992  0.15505025  0.37457317  0.35694017
 [5,] -0.15476394 -0.45689311  0.30059386  0.17007928 -0.44947710  0.09155721
 [6,] -0.25179900  0.09923688  0.72421757  0.28591804  0.14384478 -0.39301714
 [7,]  0.14936189 -0.45042646 -0.10294634 -0.20288696  0.64220223 -0.30941826
 [8,] -0.15650630 -0.37518387 -0.45674402  0.52435071 -0.24006680 -0.16487432
 [9,]  0.08280943  0.37760050 -0.07095590  0.68615925  0.38172915  0.25155723
             [,7]          [,8]        [,9]
 [1,]  0.01426529  0.5295311033  0.16128354
 [2,]  0.18406205 -0.0005812592 -0.71219681
 [3,]  0.09917056 -0.4259953369  0.57884543
 [4,] -0.34882468 -0.4825835005 -0.20352623
 [5,]  0.64768373 -0.1063191634  0.08247915
 [6,] -0.24408349  0.1866299324  0.22571622
 [7,]  0.33870309  0.2873705693  0.13259326
 [8,] -0.30042330  0.4194222320 -0.01411737
 [9,]  0.38776191  0.0246223850 -0.12143918

1-2 主成分の選出

 主成分分析の結果pr1のsummary( )と,固有値のグラフ化を行う。

summary(pr1) # 主成分分析の結果pr1の要約
Importance of components:
                          PC1    PC2    PC3    PC4     PC5    PC6     PC7
Standard deviation     1.3480 1.2763 1.0299 0.9839 0.93633 0.8975 0.84341
Proportion of Variance 0.2019 0.1810 0.1179 0.1076 0.09741 0.0895 0.07904
Cumulative Proportion  0.2019 0.3829 0.5008 0.6083 0.70574 0.7952 0.87428
                           PC8     PC9
Standard deviation     0.76150 0.74271
Proportion of Variance 0.06443 0.06129
Cumulative Proportion  0.93871 1.00000
  • スクリー基準: 下記のグラフ(スクリープロット)で,傾きがなだらかになる前までを採用する基準もよく用いられる。
  • ガットマン・カイザー基準(ガットマン基準): 固有値が1を超えるものを採用する。固有値は分散を意味しており,元の変数1個分以上の情報量を持っていると云う事になる。
  • 累積寄与率基準: 累積寄与率が50%(或いは70%)以上になるところまで採用する。
plot(pr1, 
     type = "l",
     main = "主成分分析の固有値プロット"
     )

abline(h = 1.0, lty = "dotted", col = "red")

ガットマン・カイザー基準ではぎりぎり3つ,スクリー基準では2つの主成分までを採用するのが適切だろう。
累積寄与率は下記で求められ,第3主成分までで辛うじて50%を超える5

round(cumsum(pr1$sdev^2)/sum(pr1$sdev^2)*100, 1)
[1]  20.2  38.3  50.1  60.8  70.6  79.5  87.4  93.9 100.0

1-3 主成分と元の変数の関係の解釈

主成分得点

 主成分分析の結果をオブジェクトpr1に格納してあるが,各ケースの主成分得点はpr1$xで取り出せる。
主成分得点は最大の9つまで算出されており,それが有効ケース数だけある。
pr1$xをすべて表示させると長大になるので,head( )関数を使って最初の10ケースを(四捨五入して)表示してみる。

round(head(pr1$x, n = 10), 3)
      PC1    PC2    PC3    PC4    PC5    PC6    PC7    PC8    PC9
1  -2.146  0.356 -0.465  0.371 -0.126 -0.802 -0.022  0.019  1.075
2   1.435  1.102 -2.221  0.035  0.014  0.518  0.024  0.107 -0.392
3  -2.140  0.557 -0.849 -1.660 -1.200  0.465  0.916  0.561  0.339
4  -0.186  2.319 -0.132 -0.253  0.024 -0.606  0.553  0.903 -1.055
5   1.255  0.764 -0.095  0.532 -0.112 -0.961  1.429  0.893  0.876
6   0.332  1.619  0.980  0.310  0.341  0.348  0.381 -1.511 -0.850
7   0.407  0.083 -1.727 -1.631  0.283  1.107  0.384  1.108 -0.678
8  -0.967 -0.278 -0.079  0.823 -0.589 -1.665 -0.102 -0.064 -0.660
9  -2.368 -0.240  0.614  1.268 -0.109  0.142  0.007 -0.917  0.824
10  2.074  0.377  0.701 -0.463  1.050 -0.075 -0.298 -0.298  0.517

 主成分ヴェクトルpr1$rotationも表示させてみよう。

round(pr1$rotation, 3)
             PC1    PC2    PC3    PC4    PC5    PC6    PC7    PC8    PC9
NetShop    0.498 -0.056 -0.044  0.244 -0.101  0.609  0.014 -0.530  0.161
Devices    0.555 -0.116  0.063  0.135 -0.046 -0.337  0.184  0.001 -0.712
SNS        0.514 -0.149  0.372 -0.023 -0.095 -0.199  0.099  0.426  0.579
Books      0.198  0.506 -0.129 -0.155 -0.375  0.357 -0.349  0.483 -0.204
Library    0.155  0.457 -0.301 -0.170  0.449  0.092  0.648  0.106  0.082
Comics     0.252 -0.099 -0.724 -0.286 -0.144 -0.393 -0.244 -0.187  0.226
NewsPaper -0.149  0.450  0.103  0.203 -0.642 -0.309  0.339 -0.287  0.133
Volunteer  0.157  0.375  0.457 -0.524  0.240 -0.165 -0.300 -0.419 -0.014
Smoking   -0.083 -0.378  0.071 -0.686 -0.382  0.252  0.388 -0.025 -0.121

 第1主成分得点はpr1$x[,1]で取り出せるが,元のデータ行列を標準化したものscale(d11)と第1主成分ヴェクトルpr1$rotation[, 1]から主成分得点を手動で合成することもできる。以下のようにすると先頭10ケースについてその二つを並べて比較し,完全に一致していることが確認できる。%*%は行列の積の演算子である。

第一主成分得点

score1 <- scale(d11) %*% pr1$rotation[ , 1]

cbind(pr1$x[ , 1], score1)[1:10, ]
         [,1]       [,2]
1  -2.1456084 -2.1456084
2   1.4349870  1.4349870
3  -2.1404049 -2.1404049
4  -0.1859943 -0.1859943
5   1.2554234  1.2554234
6   0.3320614  0.3320614
7   0.4069525  0.4069525
8  -0.9670763 -0.9670763
9  -2.3684490 -2.3684490
10  2.0735540  2.0735540

第二主成分得点

score2 <- scale(d11) %*% pr1$rotation[ , 2]

cbind(pr1$x[ , 2], score2)[1:10, ]
          [,1]        [,2]
1   0.35576529  0.35576529
2   1.10189384  1.10189384
3   0.55732764  0.55732764
4   2.31877146  2.31877146
5   0.76404437  0.76404437
6   1.61947086  1.61947086
7   0.08257568  0.08257568
8  -0.27831033 -0.27831033
9  -0.23997013 -0.23997013
10  0.37746106  0.37746106

主成分負荷量

 主成分負荷量(主成分得点と元の変数との積率相関係数)は以下の通り。

cor(scale(d11), pr1$x[, 1:2])
                 PC1         PC2
NetShop    0.6713545 -0.07140497
Devices    0.7476487 -0.14830796
SNS        0.6926222 -0.19019156
Books      0.2674373  0.64617703
Library    0.2086271  0.58312909
Comics     0.3394336 -0.12665525
NewsPaper -0.2013449  0.57487576
Volunteer  0.2109758  0.47884423
Smoking   -0.1116299 -0.48192855

 主成分負荷量は,主成分分析の結果の情報から以下の様にも求められる。

t(pr1$rotation) * pr1$sdev
        NetShop       Devices         SNS      Books     Library     Comics
PC1  0.67135446  0.7476487053  0.69262221  0.2674373  0.20862706  0.3394336
PC2 -0.07140497 -0.1483079572 -0.19019156  0.6461770  0.58312909 -0.1266552
PC3 -0.04526809  0.0648040732  0.38322098 -0.1325735 -0.30959289 -0.7458988
PC4  0.23993480  0.1332876775 -0.02290123 -0.1525536 -0.16734065 -0.2813142
PC5 -0.09423635 -0.0426884849 -0.08879512 -0.3507252  0.42086021 -0.1346866
PC6  0.54643618 -0.3022298795 -0.17826637  0.3203523  0.08217222 -0.3527313
PC7  0.01203146  0.1552393548  0.08364122 -0.2942014  0.54626145 -0.2058619
PC8 -0.40323673  0.0004426276  0.32439448  0.3674862  0.08096180 -0.1421183
PC9  0.11978737 -0.5289577776  0.42991598 -0.1511616  0.06125833  0.1676424
      NewsPaper   Volunteer     Smoking
PC1 -0.20134492  0.21097582 -0.11162994
PC2  0.57487576  0.47884423 -0.48192855
PC3  0.10602830  0.47041780  0.07308014
PC4  0.19962007 -0.51590758 -0.67511067
PC5 -0.60131510  0.22478245 -0.35742557
PC6 -0.27770161 -0.14797402  0.22577157
PC7  0.28566479 -0.25337932  0.32704138
PC8 -0.21883203 -0.31938907 -0.01874989
PC9  0.09847873 -0.01048515 -0.09019445

 t( )は転置行列を与える関数である。

t((t(pr1$rotation) * pr1$sdev)[1:2,])
                 PC1         PC2
NetShop    0.6713545 -0.07140497
Devices    0.7476487 -0.14830796
SNS        0.6926222 -0.19019156
Books      0.2674373  0.64617703
Library    0.2086271  0.58312909
Comics     0.3394336 -0.12665525
NewsPaper -0.2013449  0.57487576
Volunteer  0.2109758  0.47884423
Smoking   -0.1116299 -0.48192855

biplot

 各ケースの位置関係と,元々の各変数の位置関係を同時に図示するのが,biplot( )関数である。

  第1主成分と第2主成分の関係を図示するには,biplot(pr1)だけでよい(が,見にくい)。

biplot(pr1)

 いくつかのグラフオプションを指定して描いてみる。
各変数は主成分ヴェクトルの定数倍(定数はケース数の平方根×標準偏差)でプロットされ(上目盛りと右目盛り),各ケースは主成分得点の定数倍(ケース数の平方根×標準偏差の逆数)でプロットされている(下目盛りと左目盛り)。
ケース数が多いとケースのプロットはあまり役に立たない6
目盛りの値自体は気にせず,変数相互の位置関係を読み取るとよい。

biplot(pr1, 
       cex    = c(0.5, 0.8), 
       col    = c("#00000040", "red"),
       font   = 2, 
       family = "serif",
       xlab   = "第1主成分",
       ylab   = "第2主成分")

  • 予想される事だが,NetShop,Devices,SNSはかなり類似性が強く,Comicsも第2主成分に関してはこれらと近い。
  • Books, Library, Volunteerは近く,NewsPaperは第2主成分についてはこれらと近い。
  • Smokingは第1主成分はNewsPaperとやや近い7

2 探索的因子分析(Exploratory Factor Analysis)

(探索的)因子分析(EFA; Exploratory Factor Analysis)のモデルを図示すると以下の様になる。
潜在変数と観測変数の間のパス=矢印(規定関係)が主成分分析とは逆であるのに加え,観測変数にはそれ以外に誤差(独自因子)からのパスも引かれている8

DiagrammeRによるEFAの作図
grViz("
digraph EFA {
  graph [rankdir = TB, label = <<I>Exploratory Factor Analysis</I>>, labelloc = t];
  factor1[label = <factor&#8321;>];
  factor2[label = <factor&#8322;>];
  var1[shape=box, label = <var&#8321;>];
  var2[shape=box, label = <var&#8322;>];
  var3[shape=box, label = <var&#8323;>];
  var4[shape=box, label = <var&#8324;>];
  var5[shape=box, label = <var&#8325;>];
  var6[shape=box, label = <var&#8326;>];
  e1[shape=none, label = <e&#8321;>];
  e2[shape=none, label = <e&#8322;>];
  e3[shape=none, label = <e&#8323;>];
  e4[shape=none, label = <e&#8324;>];
  e5[shape=none, label = <e&#8325;>];
  e6[shape=none, label = <e&#8326;>];
  factor1 -> var1;
  factor1 -> var2;
  factor1 -> var3;
  factor1 -> var4;
  factor1 -> var5;
  factor1 -> var6;
  factor2 -> var1;
  factor2 -> var2;
  factor2 -> var3;
  factor2 -> var4;
  factor2 -> var5;
  factor2 -> var6;
  e1 -> var1
  e2 -> var2
  e3 -> var3
  e4 -> var4
  e5 -> var5
  e6 -> var6
  { rank = same; factor1; factor2; }
  { rank = same; var1; var2; var3; var4; var5; var6; }
  { rank = same; e1; e2; e3; e4; e5; e6; }
  { rank = max; e1; e2; e3; e4; e5; e6; }
}")

 Rでのこうしたグラフの描き方については,超初心者向けのRガイド DAG. Directed Acyclic Graphを参照の事。

2-1 潜在変数(latent variable)から観測変数(observed variable)への影響

例として,6変数から3因子を抽出するモデル

\[x_{1}=a_{11}f_{1}+a_{12}f_{2}+a_{13}f_{3}+\epsilon_{1}\] \[x_{2}=a_{21}f_{1}+a_{22}f_{2}+a_{23}f_{3}+\epsilon_{2}\] \[x_{3}=a_{31}f_{1}+a_{32}f_{2}+a_{33}f_{3}+\epsilon_{3}\] \[x_{4}=a_{41}f_{1}+a_{42}f_{2}+a_{43}f_{3}+\epsilon_{4}\] \[x_{5}=a_{51}f_{1}+a_{52}f_{2}+a_{53}f_{3}+\epsilon_{5}\] \[x_{6}=a_{61}f_{1}+a_{62}f_{2}+a_{63}f_{3}+\epsilon_{6}\]

2-2 因子の選出

 d11を固有値分解した結果の固有値のスクリープロットを,色々と装飾しながら描いてみる9
赤が各因子の固有値の大きさ,青は累積割合である。

# d11を固有値分解し,その固有値の累積割合を計算してヴェクトルに格納
EV1 <- eigen(cor(d11))$values
cum.prop <- cumsum(EV1/sum(EV1))
スクリープロットと累積寄与率の重ね書き
# 各固有値のグラフ
plot(EV1, 
     type   = "b", 
     family = "serif",
     col    = "red",
     xlab   = "因子番号",
     ylab   = "固有値",
     main   = "9変数の固有値分解の結果",
     yaxt = "n")

axis(side     = 2, 
     las      = 1, 
     col      = "red",
     col.axis = "red", 
     family   = "serif")

abline(h   = 1, 
       col = "red")

par(new = T) # グラフの重ね描き

# 固有値の累積割合のグラフ
plot(cum.prop, 
     type = "b", 
     col  = "blue",
     axes = F, 
     xlab = "", 
     ylab = "",
     pch  = 4,
     lty  = "dashed")

axis(side     = 4,
     col      = "blue",
     col.axis = "blue",
     family   = "serif")

abline(h   = .6, 
       col = "blue",
       lty = "dashed")

 適切な因子数を決定する為に,やや専門的な平行分析を行ってみる。
パッケイジpsychが必要になるので,インストールしていなければ,install.packages(“psych”) としてインストールする10
 この分析は乱数を発生させて,乱数の相関係数行列を固有値分解した結果と比較する為(清水裕士「因子分析における因子数選択のための基準」2026年2月28日){target=“reference”},場合によっては何度か繰り返すうちに適切な因子数が1だけ変化する事が有り得る。この分析例では,2もしくは3の因子数が推奨される。  分析のたびにグラフを出力する。赤い点線で表されているシミュレイションの結果よりも固有値が大きければ採用すべきとなる11

psych::fa.parallel(d11, SMC = TRUE, fa = "fa")

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

2-3 因子負荷量(factor loadings)と寄与率(contribution)

 Rで因子分析を行う関数も複数あるが,まずは標準の因子分析の関数factanal( )で分析する。

因子数の指定

 独自因子(言い換えれば誤差)Uniquenesses,因子負荷量Loadings(線型方程式の係数),因子寄与(寄与度)SS loadings(因子負荷量の二乗和),分散割合Proportion Var,累積分散割合Cumulative Var,因子数についての検定結果を確認しよう。

factanal(d11, factors = 3)

Call:
factanal(x = d11, factors = 3)

Uniquenesses:
  NetShop   Devices       SNS     Books   Library    Comics NewsPaper Volunteer 
    0.723     0.621     0.376     0.648     0.799     0.866     0.825     0.802 
  Smoking 
    0.912 

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.364           0.367 
Devices    0.516           0.335 
SNS        0.787                 
Books              0.588         
Library            0.438         
Comics                     0.359 
NewsPaper -0.120   0.338  -0.216 
Volunteer  0.188   0.345  -0.210 
Smoking           -0.295         

               Factor1 Factor2 Factor3
SS loadings      1.077   0.871   0.480
Proportion Var   0.120   0.097   0.053
Cumulative Var   0.120   0.216   0.270

Test of the hypothesis that 3 factors are sufficient.
The chi square statistic is 22.35 on 12 degrees of freedom.
The p-value is 0.0338 

 因子数の検定結果は,4因子の場合も紹介しよう。「4因子で十分である」とのゼロ仮説は5%水準で棄却されなかった。

factanal(d11, factors = 4)

Call:
factanal(x = d11, factors = 4)

Uniquenesses:
  NetShop   Devices       SNS     Books   Library    Comics NewsPaper Volunteer 
    0.722     0.579     0.590     0.663     0.819     0.005     0.836     0.005 
  Smoking 
    0.889 

Loadings:
          Factor1 Factor2 Factor3 Factor4
NetShop    0.508                   0.119 
Devices    0.640   0.103                 
SNS        0.622           0.115         
Books                      0.101   0.562 
Library                    0.103   0.404 
Comics     0.121   0.989                 
NewsPaper -0.174                   0.356 
Volunteer                  0.974   0.206 
Smoking                           -0.328 

               Factor1 Factor2 Factor3 Factor4
SS loadings      1.111   1.013   0.989   0.779
Proportion Var   0.123   0.113   0.110   0.087
Cumulative Var   0.123   0.236   0.346   0.432

Test of the hypothesis that 4 factors are sufficient.
The chi square statistic is 12.49 on 6 degrees of freedom.
The p-value is 0.052 

 標準のfactanal( )関数では,斜交promax解の因子間相関係数行列が正しく出力されない問題があったが(旧版サポートウェブ第11章 2-3 因子負荷量(factor loadings)と寄与率(contribution)),現在は解消されている様である。

factanal(, rotation = "promax")

Factor Correlationsの欄が因子間相関。

factanal_promax <- factanal(d11, factors = 3, rotation = "promax")
factanal_promax

Call:
factanal(x = d11, factors = 3, rotation = "promax")

Uniquenesses:
  NetShop   Devices       SNS     Books   Library    Comics NewsPaper Volunteer 
    0.723     0.621     0.376     0.648     0.799     0.866     0.825     0.802 
  Smoking 
    0.912 

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.138   0.166   0.427 
Devices            0.339   0.398 
SNS                0.769         
Books      0.603                 
Library    0.458  -0.111   0.126 
Comics            -0.111   0.398 
NewsPaper  0.318          -0.227 
Volunteer  0.318   0.243  -0.201 
Smoking   -0.303                 

               Factor1 Factor2 Factor3
SS loadings      0.899   0.825   0.621
Proportion Var   0.100   0.092   0.069
Cumulative Var   0.100   0.192   0.261

Factor Correlations:
        Factor1 Factor2 Factor3
Factor1   1.000   0.139  -0.105
Factor2   0.139   1.000   0.378
Factor3  -0.105   0.378   1.000

Test of the hypothesis that 3 factors are sufficient.
The chi square statistic is 22.35 on 12 degrees of freedom.
The p-value is 0.0338 

因子間相関のみ計算して表示12

solve(t(factanal_promax$rotmat) %*% factanal_promax$rotmat)
           [,1]      [,2]       [,3]
[1,]  1.0000000 0.1388985 -0.1050634
[2,]  0.1388985 1.0000000  0.3780262
[3,] -0.1050634 0.3780262  1.0000000

promax(factanal(, rotation = "none")$loadings)

標準で(回転させない)初期解を求めてからpromax( )関数に与える

factanal_none <- factanal(d11, factors = 3, rotation = "none")
factanal_none_to_promax <- promax(factanal_none$loadings)
factanal_none_to_promax
$loadings

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.166   0.138   0.427 
Devices    0.339           0.398 
SNS        0.769                 
Books              0.603         
Library   -0.111   0.458   0.126 
Comics    -0.111           0.398 
NewsPaper          0.318  -0.227 
Volunteer  0.243   0.318  -0.201 
Smoking           -0.303         

               Factor1 Factor2 Factor3
SS loadings      0.825   0.899   0.621
Proportion Var   0.092   0.100   0.069
Cumulative Var   0.092   0.192   0.261

$rotmat
           [,1]       [,2]       [,3]
[1,]  0.8072816 0.02995755 0.35516522
[2,] -0.1317796 1.01376498 0.02801236
[3,] -0.7370832 0.14863144 1.03697397

因子間相関行列を求める。
第1因子と第2因子の順番が入れ替わっているので注意が必要だが,値はすべて一致している。

solve(t(factanal_none_to_promax$rotmat) %*% factanal_none_to_promax$rotmat)
          [,1]       [,2]       [,3]
[1,] 1.0000000  0.1388985  0.3780262
[2,] 0.1388985  1.0000000 -0.1050634
[3,] 0.3780262 -0.1050634  1.0000000

psychパッケイジのfa( )関数では以下の通り13

fa_Promax <- psych::fa(d11, nfactors = 3, rotate = "Promax", fm = "ml")
fa_Promax; fa_Promax$Phi
Factor Analysis using method =  ml
Call: psych::fa(r = d11, nfactors = 3, rotate = "Promax", fm = "ml")
Standardized loadings (pattern matrix) based upon correlation matrix
            ML2   ML1   ML3    h2   u2 com
NetShop    0.14  0.17  0.43 0.277 0.72 1.5
Devices    0.05  0.34  0.40 0.379 0.62 2.0
SNS       -0.08  0.77  0.07 0.624 0.38 1.0
Books      0.60 -0.04  0.09 0.352 0.65 1.1
Library    0.46 -0.11  0.13 0.201 0.80 1.3
Comics     0.06 -0.11  0.40 0.134 0.87 1.2
NewsPaper  0.32 -0.06 -0.23 0.175 0.82 1.9
Volunteer  0.32  0.24 -0.20 0.198 0.80 2.6
Smoking   -0.30  0.06 -0.05 0.088 0.91 1.1

                       ML2  ML1  ML3
SS loadings           0.88 0.88 0.67
Proportion Var        0.10 0.10 0.07
Cumulative Var        0.10 0.20 0.27
Proportion Explained  0.36 0.36 0.28
Cumulative Proportion 0.36 0.72 1.00

 With factor correlations of 
      ML2  ML1   ML3
ML2  1.00 0.14 -0.11
ML1  0.14 1.00  0.38
ML3 -0.11 0.38  1.00

Mean item complexity =  1.5
Test of the hypothesis that 3 factors are sufficient.

df null model =  36  with the objective function =  0.72 with Chi Square =  263.81
df of  the model are 12  and the objective function was  0.06 

The root mean square of the residuals (RMSR) is  0.03 
The df corrected root mean square of the residuals is  0.05 

The harmonic n.obs is  373 with the empirical chi square  13.35  with prob <  0.34 
The total n.obs was  373  with Likelihood Chi Square =  22.35  with prob <  0.034 

Tucker Lewis Index of factoring reliability =  0.863
RMSEA index =  0.048  and the 90 % confidence intervals are  0.013 0.079
BIC =  -48.71
Fit based upon off diagonal values = 0.95
Measures of factor score adequacy             
                                                   ML2  ML1   ML3
Correlation of (regression) scores with factors   0.74 0.76  0.65
Multiple R square of scores with factors          0.54 0.57  0.42
Minimum correlation of possible factor scores     0.08 0.14 -0.17
           ML2       ML1        ML3
ML2  1.0000000 0.1389025 -0.1050531
ML1  0.1389025 1.0000000  0.3780471
ML3 -0.1050531 0.3780471  1.0000000

無回転解の比較: factanal( ), psych::fa( )

factanal( )は最尤法(ml)に固定されている。
fa( )はfm(factoring method)がdefaultで”minres”(minimum residual)なので,明示的にmlを指定しなければならない。

# factanal_none <- factanal( d11, factors = 3,  rotation = "none")
fa_none    <- psych::fa(d11, nfactors = 3, rotate   = "none", fm = "ml")

左にfactanal( ),右にfa( )の結果を並べて示す。
独自性は,小数第4位までは一致している様である。

cbind(factanal_none$uniquenesses, fa_none$uniquenesses)
               [,1]      [,2]
NetShop   0.7233895 0.7233957
Devices   0.6211288 0.6211187
SNS       0.3763595 0.3763718
Books     0.6478020 0.6478006
Library   0.7992243 0.7992272
Comics    0.8660744 0.8660722
NewsPaper 0.8247093 0.8247059
Volunteer 0.8017916 0.8017873
Smoking   0.9122691 0.9122755

因子負荷量も完全に一致している。

print(factanal_none$loadings,
      digits = 4,
      cutoff = 0)

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.4519  0.0856  0.2550
Devices    0.5879  0.0080  0.1822
SNS        0.7618 -0.0702 -0.1959
Books      0.0851  0.5858  0.0430
Library    0.0257  0.4359  0.1005
Comics     0.1631  0.0108  0.3274
NewsPaper -0.1677  0.3437 -0.1704
Volunteer  0.1309  0.3457 -0.2481
Smoking   -0.0047 -0.2941 -0.0346

               Factor1 Factor2 Factor3
SS loadings     1.2099  0.8697  0.3476
Proportion Var  0.1344  0.0966  0.0386
Cumulative Var  0.1344  0.2311  0.2697
print(fa_none$loadings,
      digits = 4,
      cutoff = 0)

Loadings:
          ML1     ML2     ML3    
NetShop    0.4519  0.0856  0.2550
Devices    0.5879  0.0080  0.1822
SNS        0.7618 -0.0702 -0.1959
Books      0.0851  0.5858  0.0430
Library    0.0257  0.4359  0.1005
Comics     0.1631  0.0108  0.3274
NewsPaper -0.1677  0.3437 -0.1704
Volunteer  0.1309  0.3457 -0.2481
Smoking   -0.0047 -0.2941 -0.0346

                  ML1    ML2    ML3
SS loadings    1.2099 0.8697 0.3476
Proportion Var 0.1344 0.0966 0.0386
Cumulative Var 0.1344 0.2311 0.2697

varimax回転解の比較

かつては最もポピュラーであった直交解のVarimax解を比較する。

factanal_v <- factanal( d11, factors = 3,  rotation = "varimax")
fa_v       <- psych::fa(d11, nfactors = 3, rotate   = "varimax", fm = "ml")

直交回転しようがしまいが,独自性はそれぞれ変化していない。

cbind(factanal_v$uniquenesses, fa_v$uniquenesses)
               [,1]      [,2]
NetShop   0.7233895 0.7233957
Devices   0.6211288 0.6211187
SNS       0.3763595 0.3763718
Books     0.6478020 0.6478006
Library   0.7992243 0.7992272
Comics    0.8660744 0.8660722
NewsPaper 0.8247093 0.8247059
Volunteer 0.8017916 0.8017873
Smoking   0.9122691 0.9122755

因子負荷量もほぼ完全に一致している。

print(factanal_v$loadings,
      digits = 4,
      cutoff = 0)

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.3640  0.0984  0.3666
Devices    0.5159  0.0226  0.3350
SNS        0.7873 -0.0577  0.0200
Books      0.0611  0.5879  0.0530
Library   -0.0093  0.4378  0.0951
Comics     0.0676  0.0188  0.3592
NewsPaper -0.1202  0.3377 -0.2163
Volunteer  0.1881  0.3446 -0.2099
Smoking    0.0095 -0.2946 -0.0289

               Factor1 Factor2 Factor3
SS loadings     1.0769  0.8708  0.4795
Proportion Var  0.1197  0.0968  0.0533
Cumulative Var  0.1197  0.2164  0.2697
print(fa_v$loadings,
      digits = 4,
      cutoff = 0)

Loadings:
          ML1     ML2     ML3    
NetShop    0.3641  0.0984  0.3666
Devices    0.5159  0.0226  0.3350
SNS        0.7873 -0.0577  0.0200
Books      0.0611  0.5879  0.0530
Library   -0.0093  0.4378  0.0951
Comics     0.0676  0.0188  0.3592
NewsPaper -0.1202  0.3377 -0.2163
Volunteer  0.1881  0.3446 -0.2099
Smoking    0.0095 -0.2946 -0.0289

                  ML1    ML2    ML3
SS loadings    1.0769 0.8708 0.4795
Proportion Var 0.1197 0.0968 0.0533
Cumulative Var 0.1197 0.2164 0.2697

promax回転解の比較

斜交回転で最もポピュラーなpromax解を比較する。
但し,psych::fa( ) では,rotate = “promax”と”Promax”で計算方法が異なるので注意が必要!
fa function: RDocumentation(2026年3月1日閲覧)14

# factanal_promax <- factanal(d11, factors = 3,  rotation = "promax")
# fa_Promax      <- psych::fa(d11, nfactors = 3, rotate = "Promax", fm = "ml")
fa_promax  <- psych::fa(d11, nfactors = 3, rotate   = "promax", fm = "ml")
Loading required namespace: GPArotation

斜交回転しようがしまいが,独自性は変化しない。

cbind(factanal_promax$uniquenesses, fa_promax$uniquenesses, fa_Promax$uniquenesses)
               [,1]      [,2]      [,3]
NetShop   0.7233895 0.7233957 0.7233957
Devices   0.6211288 0.6211187 0.6211187
SNS       0.3763595 0.3763718 0.3763718
Books     0.6478020 0.6478006 0.6478006
Library   0.7992243 0.7992272 0.7992272
Comics    0.8660744 0.8660722 0.8660722
NewsPaper 0.8247093 0.8247059 0.8247059
Volunteer 0.8017916 0.8017873 0.8017873
Smoking   0.9122691 0.9122755 0.9122755

因子負荷量になると,fa_promaxだけが大きく変化する15
因子間相関行列もこれだけ一致しない。

print(factanal_promax$loadings,
      digits = 4,
      cutoff = 0)

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.1383  0.1656  0.4274
Devices    0.0528  0.3393  0.3979
SNS       -0.0775  0.7687  0.0654
Books      0.6028 -0.0402  0.0912
Library    0.4576 -0.1107  0.1255
Comics     0.0645 -0.1111  0.3978
NewsPaper  0.3181 -0.0550 -0.2267
Volunteer  0.3175  0.2430 -0.2011
Smoking   -0.3035  0.0605 -0.0458

               Factor1 Factor2 Factor3
SS loadings     0.8989  0.8253  0.6215
Proportion Var  0.0999  0.0917  0.0691
Cumulative Var  0.0999  0.1916  0.2606
factanal_promax$rotmat
           [,1]       [,2]       [,3]
[1,] 0.02995755  0.8072816 0.35516522
[2,] 1.01376498 -0.1317796 0.02801236
[3,] 0.14863144 -0.7370832 1.03697397
# 因子間相関行列を求める
solve(t(factanal_promax$rotmat) %*% factanal_promax$rotmat)
           [,1]      [,2]       [,3]
[1,]  1.0000000 0.1388985 -0.1050634
[2,]  0.1388985 1.0000000  0.3780262
[3,] -0.1050634 0.3780262  1.0000000
print(promax(factanal_none$loadings), 
      digits = 4, 
      cutoff = 0)
$loadings

Loadings:
          Factor1 Factor2 Factor3
NetShop    0.1656  0.1383  0.4274
Devices    0.3393  0.0528  0.3979
SNS        0.7687 -0.0775  0.0654
Books     -0.0402  0.6028  0.0912
Library   -0.1107  0.4576  0.1255
Comics    -0.1111  0.0645  0.3978
NewsPaper -0.0550  0.3181 -0.2267
Volunteer  0.2430  0.3175 -0.2011
Smoking    0.0605 -0.3035 -0.0458

               Factor1 Factor2 Factor3
SS loadings     0.8253  0.8989  0.6215
Proportion Var  0.0917  0.0999  0.0691
Cumulative Var  0.0917  0.1916  0.2606

$rotmat
        [,1]    [,2]    [,3]
[1,]  0.8073 0.02996 0.35517
[2,] -0.1318 1.01376 0.02801
[3,] -0.7371 0.14863 1.03697
solve(t(promax(factanal_none$loadings)$rotmat) %*% promax(factanal_none$loadings)$rotmat)
          [,1]       [,2]       [,3]
[1,] 1.0000000  0.1388985  0.3780262
[2,] 0.1388985  1.0000000 -0.1050634
[3,] 0.3780262 -0.1050634  1.0000000
print(fa_promax$loadings,  digits = 4, cutoff = 0)

Loadings:
          ML1     ML2     ML3    
NetShop    0.2969  0.1058  0.3369
Devices    0.4690  0.0066  0.2742
SNS        0.8295 -0.1492 -0.1098
Books      0.0132  0.5967  0.0806
Library   -0.0602  0.4582  0.1281
Comics    -0.0086  0.0592  0.3725
NewsPaper -0.1022  0.3282 -0.1912
Volunteer  0.2210  0.2995 -0.2340
Smoking    0.0362 -0.3041 -0.0493

                  ML1    ML2    ML3
SS loadings    1.0608 0.8929 0.4561
Proportion Var 0.1179 0.0992 0.0507
Cumulative Var 0.1179 0.2171 0.2677
fa_promax$Phi
          ML1        ML2        ML3
ML1 1.0000000  0.1424179  0.3238314
ML2 0.1424179  1.0000000 -0.1395861
ML3 0.3238314 -0.1395861  1.0000000
print(fa_Promax$loadings,  digits = 4, cutoff = 0)

Loadings:
          ML2     ML1     ML3    
NetShop    0.1383  0.1656  0.4273
Devices    0.0528  0.3393  0.3979
SNS       -0.0775  0.7687  0.0654
Books      0.6028 -0.0402  0.0912
Library    0.4576 -0.1107  0.1255
Comics     0.0645 -0.1111  0.3978
NewsPaper  0.3181 -0.0550 -0.2267
Volunteer  0.3175  0.2430 -0.2011
Smoking   -0.3035  0.0605 -0.0458

                  ML2    ML1    ML3
SS loadings    0.8989 0.8253 0.6214
Proportion Var 0.0999 0.0917 0.0690
Cumulative Var 0.0999 0.1916 0.2606
fa_Promax$Phi
           ML2       ML1        ML3
ML2  1.0000000 0.1389025 -0.1050531
ML1  0.1389025 1.0000000  0.3780471
ML3 -0.1050531 0.3780471  1.0000000

2-4 因子の解釈

プロマックス解の結果を出力する。上のオブジェクトの中から,fa_Promax を使用しておこう。

pro1 <- promax(fa_none$loadings) # 初期解のプロマックス回転の結果をpro1に保存
print(fa_Promax$loadings, cutoff = 0) # pro1の中のloadingsの情報を,省略せず表示

Loadings:
          ML2    ML1    ML3   
NetShop    0.138  0.166  0.427
Devices    0.053  0.339  0.398
SNS       -0.078  0.769  0.065
Books      0.603 -0.040  0.091
Library    0.458 -0.111  0.126
Comics     0.064 -0.111  0.398
NewsPaper  0.318 -0.055 -0.227
Volunteer  0.318  0.243 -0.201
Smoking   -0.303  0.061 -0.046

                 ML2   ML1   ML3
SS loadings    0.899 0.825 0.621
Proportion Var 0.100 0.092 0.069
Cumulative Var 0.100 0.192 0.261
fa_Promax$Phi
           ML2       ML1        ML3
ML2  1.0000000 0.1389025 -0.1050531
ML1  0.1389025 1.0000000  0.3780471
ML3 -0.1050531 0.3780471  1.0000000

グラフ

グラフを作図するには,以下の様に biplot( ) を使用する事も出来る。

biplot(fa_Promax$scores, fa_Promax$loadings)

biplot(fa_Promax$scores, fa_Promax$loadings, 
       cex = c(0.5, 0.8), 
       col = c("#00000040", "red"),
       font = 2,  # 1 通常,2 bold, 3 italic, 4 bold & italic
       family = "serif")

必要最小限の情報で読み取りが容易である。

plot(fa_Promax$loadings[, c(1,2)], 
     xlim = c(min(fa_Promax$loadings[, 1]) -.1, max(fa_Promax$loadings[, 1]) +.1), 
     ylim = c(min(fa_Promax$loadings[, 2]) -.1, max(fa_Promax$loadings[, 2]) +.1),
     xlab = "第1因子",
     ylab = "第2因子",
     pch  = 16,
     col  = "#0202ff60")

abline(h = 0, v = 0, 
       lty = "dashed", 
       col = "gray") # 原点を通る座標を追加

text(fa_Promax$loadings[,c(1,2)] + .01, names(d11), 
     family = "serif", 
     col    = "#B22222")

第1因子と第3因子
plot(fa_Promax$loadings[, c(1, 3)], 
     xlim = c(min(fa_Promax$loadings[, 1]) -.1, max(fa_Promax$loadings[, 1]) +.1), 
     ylim = c(min(fa_Promax$loadings[, 3]) -.1, max(fa_Promax$loadings[, 3]) +.1),
     xlab = "第1因子",
     ylab = "第3因子",
     pch  = 16,
     col  = "#0202ff60")

abline(h = 0, v = 0, 
       lty = "dashed", 
       col = "gray") # 原点を通る座標を追加

text(fa_Promax$loadings[,c(1, 3)], names(d11), 
     family = "serif", 
     col    = "#B22222")

第2因子と第3因子
plot(fa_Promax$loadings[, c(2, 3)], 
     xlim = c(min(fa_Promax$loadings[, 2]) -.1, max(fa_Promax$loadings[, 2]) +.1), 
     ylim = c(min(fa_Promax$loadings[, 3]) -.1, max(fa_Promax$loadings[, 3]) +.1),
     xlab = "第2因子",
     ylab = "第3因子",
     pch  = 16,
     col  = "#0202ff60")

abline(h = 0, v = 0, 
       lty = "dashed", 
       col = "gray") # 原点を通る座標を追加

text(fa_Promax$loadings[,c(2, 3)], names(d11), 
     family = "serif", 
     col    = "#B22222")

psych::fa.diagram(fa_Promax$loadings, 
                  cut = .2, digits = 3, sort = F, errors = F, l.cex = .7,
                  marg = c(.5, 2.5, 1, .5), simple = F, rsize = .3, adj = 3,
                  main = "EFA ")

パッケイジ”psych”のalpha( )関数

 psychパッケイジのクロンバックのα係数による内的整合性の検討の為のalpha( )関数の結果を例示しておく。

psych::alpha(d11[ , c(1:3, 8)])
Warning in response.frequencies(x, max = max): response.frequency has been
deprecated and replaced with responseFrequecy.  Please fix your call

Reliability analysis   
Call: psych::alpha(x = d11[, c(1:3, 8)])

  raw_alpha std.alpha G6(smc) average_r  S/N   ase mean  sd median_r
      0.49      0.49    0.46       0.2 0.98 0.033  2.8 1.1     0.21

    95% confidence boundaries 
         lower alpha upper
Feldt     0.40  0.49  0.57
Duhachek  0.43  0.49  0.56

 Reliability if an item is dropped:
          raw_alpha std.alpha G6(smc) average_r  S/N alpha se  var.r med.r
NetShop        0.44      0.42    0.37      0.20 0.73    0.038 0.0364  0.12
Devices        0.28      0.31    0.26      0.13 0.46    0.043 0.0231  0.12
SNS            0.29      0.29    0.25      0.12 0.40    0.055 0.0314  0.05
Volunteer      0.54      0.61    0.51      0.34 1.54    0.032 0.0041  0.32

 Item statistics 
            n raw.r std.r r.cor r.drop mean   sd
NetShop   373  0.51  0.63  0.42  0.329  2.2 0.89
Devices   373  0.73  0.71  0.58  0.433  3.9 1.71
SNS       373  0.87  0.72  0.60  0.449  3.4 2.66
Volunteer 373  0.32  0.46  0.10  0.098  1.5 0.99

Non missing response frequency for each item
             1    2    3    4    5    6    7   8 miss
NetShop   0.25 0.44 0.23 0.09 0.00 0.00 0.00 0.0    0
Devices   0.24 0.02 0.02 0.05 0.68 0.00 0.00 0.0    0
SNS       0.24 0.39 0.05 0.02 0.05 0.01 0.04 0.2    0
Volunteer 0.73 0.11 0.10 0.04 0.02 0.00 0.00 0.0    0

Volunteerは除外した方が内的一貫性の指標は改善する事が分かる。

発展1 構造方程式モデリング(Structural Equation Modelling)

発展1-1 確証的因子分析(CFA)と構造方程式モデリング(SEM)

 構造方程式モデリング(SEM; Structural Equation Modelling)によって確証的因子分析(CFA; Confirmatory Factor Analyis)を行ってみよう。
 あくまで説明用の初歩的なものであるが,本文では省略せざるを得なかったスクリプトや出力を全て掲示する16

# 下の行はSEMの代表的な適合度指標を表示させるためのオプション
opt <- options(fit.indices = c("GFI", "AGFI", "RMSEA", "AIC", "BIC"))

model01 <- sem::specifyModel()
  Fac1 -> Devices, NA, 1 # 第1因子から"Devices"変数へのパスを固定
  Fac1 -> SNS, b13, NA # 第1因子から"SNS"変数へのパスは値を推定
  Fac1 -> Volunteer, b16, NA
  Fac2 -> Books, NA, 1 # それぞれの因子につき,どれか一つのパスは固定する。
  Fac2 -> Library, b25, NA
  Fac2 -> NewsPaper, b27, NA
  Fac2 -> Smoking, b29, NA
  Fac3 -> NetShop, NA, 1
  Fac3 -> Devices, b32, NA
  Fac3 -> Comics, b36, NA
  NetShop <-> NetShop, e01, NA # "NetShop"変数の分散
  Devices <-> Devices, e02, NA
  SNS <-> SNS, e03, NA
  Books <-> Books, e04, NA
  Library <-> Library, e05, NA
  Comics <-> Comics, e06, NA
  NewsPaper <-> NewsPaper, e07, NA
  Volunteer <-> Volunteer, e08, NA
  Smoking <-> Smoking, e09, NA
  Fac1 <-> Fac1, d01, NA # 第1因子の分散
  Fac2 <-> Fac2, d02, NA
  Fac3 <-> Fac3, d03, NA

result01 <- sem::sem(model01, cor1 <- cor(d11), N = nrow(d11)) # モデル,相関係数行列,ケース数を指定

summary(result01)
 Model Chisquare =  102.9626   Df =  26 Pr(>Chisq) = 4.107161e-11
 Goodness-of-fit index =  0.9442905
 Adjusted goodness-of-fit index =  0.9035798
 RMSEA index =  0.08920345   90% CI: (0.07151387, 0.1076236)
 AIC =  140.9626
 BIC =  -50.99846

 Normalized Residuals
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-2.4058 -0.6740  0.1787  0.3512  1.1340  5.5622 

 R-square for Endogenous Variables
  Devices       SNS Volunteer     Books   Library NewsPaper   Smoking 
   0.5579    0.6711    0.0230    0.2981    0.1747    0.1254    0.1061 
  NetShop    Comics 
   0.1368    0.0703 

 Parameter Estimates
    Estimate   Std Error  z value    Pr(>|z|)    
b13  1.9587682 1.42925458  1.3704824 1.705364e-01
b16  0.3626587 0.15657332  2.3162231 2.054609e-02
b25  0.7654931 0.22887455  3.3445967 8.240229e-04
b27  0.6487525 0.19985437  3.2461262 1.169870e-03
b29 -0.5964885 0.18981835 -3.1424174 1.675590e-03
b32  1.6162196 0.87428696  1.8486146 6.451348e-02
b36  0.7169138 0.25134362  2.8523255 4.340063e-03
e01  0.8632312 0.09757354  8.8469797 8.991977e-19
e02  0.4217627 0.23341792  1.8068993 7.077799e-02
e03  0.3288870 0.48710881  0.6751818 4.995602e-01
e04  0.7019364 0.10372196  6.7674811 1.310438e-11
e05  0.8253409 0.08238156 10.0185156 1.263869e-23
e06  0.9297053 0.07812630 11.9000307 1.183036e-32
e07  0.8745511 0.07744910 11.2919467 1.438156e-29
e08  0.9769949 0.07355238 13.2829822 2.905864e-40
e09  0.8939494 0.07623789 11.7257888 9.402109e-32
d01  0.1749160 0.13259364  1.3191885 1.871061e-01
d02  0.2980636 0.10409890  2.8632729 4.192892e-03
d03  0.1367688 0.08297217  1.6483695 9.927686e-02
                            
b13 SNS <--- Fac1           
b16 Volunteer <--- Fac1     
b25 Library <--- Fac2       
b27 NewsPaper <--- Fac2     
b29 Smoking <--- Fac2       
b32 Devices <--- Fac3       
b36 Comics <--- Fac3        
e01 NetShop <--> NetShop    
e02 Devices <--> Devices    
e03 SNS <--> SNS            
e04 Books <--> Books        
e05 Library <--> Library    
e06 Comics <--> Comics      
e07 NewsPaper <--> NewsPaper
e08 Volunteer <--> Volunteer
e09 Smoking <--> Smoking    
d01 Fac1 <--> Fac1          
d02 Fac2 <--> Fac2          
d03 Fac3 <--> Fac3          

 Iterations =  53 

modIndices( )関数を使って,どうしたらモデルが改善するかの示唆を得よう。

sem::modIndices(result01)
5 largest modification indices, A matrix (regression coefficients):
    SNS<-NetShop    Fac1<-NetShop     NetShop<-SNS    NetShop<-Fac1 
        31.83584         30.15121         29.90668         29.23949 
NetShop<-Devices 
        29.23944 

  5 largest modification indices, P matrix (variances/covariances):
   SNS<->NetShop   Fac1<->NetShop       Fac3<->SNS      Fac3<->Fac1 
        30.58013         29.23949         27.56606         24.71071 
Fac2<->Volunteer 
        22.94430 

NetShop<-Fac1から,第1因子からNetShopへのパスを追加し,‘Fac3<->Fac1’ から,第1因子と第3因子に相関を追加すると良いと考えられる。
それ以外はここでは余り妥当ではないパスと考えられる。

 update( )関数を使ってmodel01を更新する。

model02 <- update(model01)
  add, Fac1 -> NetShop, b11, NA
  add, Fac1 <-> Fac3, r13, NA

result02 <- sem(model02, cor1, N=nrow(vars1))
summary(result02)
> model02 <- update(model01)
1: add, Fac1 -> NetShop, b11, NA
2: add, Fac1 <-> Fac3, r13, NA
3: 
Read 2 records
> result02 <- sem::sem(model02, cor1, N = nrow(d11))
Warning in eval(substitute(expr), data, enclos = parent.frame()) :
  Negative parameter variances.
Model may be underidentified.
> summary(result02)

 Model Chisquare =  70.20844   Df =  24 Pr(>Chisq) = 2.033104e-06
 Goodness-of-fit index =  0.9624529
 Adjusted goodness-of-fit index =  0.9295991
 RMSEA index =  0.07194218   90% CI: (0.05273846, 0.09178894)
 AIC =  112.2084
 BIC =  -71.90944

 Normalized Residuals
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
-2.40575 -0.72883  0.00000  0.08728  0.61322  4.14093 

 R-square for Endogenous Variables
  Devices       SNS Volunteer     Books   Library NewsPaper   Smoking 
   0.5629    1.5226    0.0101    0.2981    0.1747    0.1254    0.1061 
  NetShop    Comics 
   0.1832    0.0598 

 Parameter Estimates
    Estimate    Std Error   z value    Pr(>|z|)    
b13  6.86604858 11.56035786  0.5939305 5.525586e-01
b16  0.56032444  0.49976458  1.1211768 2.622126e-01
b25  0.76549196  0.22887437  3.3445944 8.240298e-04
b27  0.64875160  0.19985423  3.2461239 1.169879e-03
b29 -0.59648763  0.18981822 -3.1424151 1.675603e-03
b32  1.87971471  1.10882022  1.6952385 9.003019e-02
b36  0.66651004  0.29221171  2.2809149 2.255348e-02
e01  0.81676057  0.09644023  8.4690854 2.473272e-17
e02  0.43711666  0.26776952  1.6324362 1.025876e-01
e03 -0.52256852  1.96807674 -0.2655224 7.906070e-01
e04  0.70193601  0.10372210  6.7674682 1.310554e-11
e05  0.82534108  0.08238154 10.0185202 1.263810e-23
e06  0.94020403  0.07686634 12.2316734 2.105558e-34
e07  0.87455123  0.07744909 11.2919495 1.438110e-29
e08  0.98985990  0.07375361 13.4211720 4.544685e-41
e09  0.89394958  0.07623789 11.7257915 9.401807e-32
d01  0.03229707  0.07440190  0.4340893 6.642236e-01
d02  0.29806400  0.10409907  2.8632724 4.192899e-03
d03  0.13460418  0.10146997  1.3265421 1.846602e-01
b11  0.85517431  0.51204448  1.6701172 9.489617e-02
r13  0.01462606  0.01980898  0.7383548 4.602989e-01
                            
b13 SNS <--- Fac1           
b16 Volunteer <--- Fac1     
b25 Library <--- Fac2       
b27 NewsPaper <--- Fac2     
b29 Smoking <--- Fac2       
b32 Devices <--- Fac3       
b36 Comics <--- Fac3        
e01 NetShop <--> NetShop    
e02 Devices <--> Devices    
e03 SNS <--> SNS            
e04 Books <--> Books        
e05 Library <--> Library    
e06 Comics <--> Comics      
e07 NewsPaper <--> NewsPaper
e08 Volunteer <--> Volunteer
e09 Smoking <--> Smoking    
d01 Fac1 <--> Fac1          
d02 Fac2 <--> Fac2          
d03 Fac3 <--> Fac3          
b11 NetShop <--- Fac1       
r13 Fac3 <--> Fac1          

 Iterations =  143 

 適合度指標は改善しているが,e03のSNSの分散がマイナスとなり,本来は不適切な解になっている。警告メッセージの「Negative parameter variances.」がそれを示している。

sem::modIndices(result02)

model03 <- update(model02)
  add, Fac2 -> Volunteer, b21, NA

result03 <- sem::sem(model03, cor1, N = nrow(d11))
summary(result03)
> model03 <- update(model02)
1: add, Fac2 -> Volunteer, b21, NA
2: 
Read 1 record
> result03 <- sem::sem(model03, cor1, N = nrow(d11))
Warning in eval(substitute(expr), data, enclos = parent.frame()) :
  Negative parameter variances.
Model may be underidentified.
> summary(result03)

 Model Chisquare =  45.55356   Df =  23 Pr(>Chisq) = 0.003397699
 Goodness-of-fit index =  0.9749651
 Adjusted goodness-of-fit index =  0.9510186
 RMSEA index =  0.05134193   90% CI: (0.02886418, 0.07312731)
 AIC =  89.55356
 BIC =  -90.64274

 Normalized Residuals
      Min.    1st Qu.     Median       Mean    3rd Qu.       Max. 
-2.406e+00 -7.387e-01 -4.000e-08 -1.115e-01  5.360e-01  2.721e+00 

 R-square for Endogenous Variables
  Devices       SNS Volunteer     Books   Library NewsPaper   Smoking 
   0.5710    2.6733    0.1402    0.3192    0.1925    0.1088    0.0878 
  NetShop    Comics 
   0.1797    0.0571 

 Parameter Estimates
    Estimate     Std Error   z value    Pr(>|z|)    
b13 13.909119210 34.31474267  0.4053395 6.852280e-01
b16  0.702105756  0.69991196  1.0031344 3.157960e-01
b25  0.776506959  0.19107354  4.0639168 4.825604e-05
b27  0.583764565  0.16125231  3.6201936 2.943827e-04
b29 -0.524510416  0.15460548 -3.3925732 6.923944e-04
b32  1.856124447  1.03794179  1.7882741 7.373179e-02
b36  0.611342568  0.23728360  2.5764215 9.982886e-03
e01  0.820275499  0.10178277  8.0590802 7.687063e-16
e02  0.428987186  0.28382910  1.5114278 1.306795e-01
e03 -1.673312648  5.59739143 -0.2989451 7.649819e-01
e04  0.680754958  0.09139858  7.4482004 9.462205e-14
e05  0.807507033  0.07776918 10.3833807 2.951350e-25
e06  0.942936272  0.07565842 12.4630711 1.187094e-35
e07  0.891207333  0.07400639 12.0423028 2.129276e-33
e08  0.863636803  0.07585948 11.3846915 4.984435e-30
e09  0.912172121  0.07362036 12.3902161 2.952467e-35
d01  0.013818169  0.04279549  0.3228884 7.467798e-01
d02  0.319245043  0.09352516  3.4134669 6.414194e-04
d03  0.152683070  0.10386863  1.4699633 1.415717e-01
b11  0.917522830  0.66178601  1.3864343 1.656143e-01
r13  0.008396863  0.01841196  0.4560549 6.483505e-01
b21  0.647978387  0.16892108  3.8359829 1.250631e-04
                            
b13 SNS <--- Fac1           
b16 Volunteer <--- Fac1     
b25 Library <--- Fac2       
b27 NewsPaper <--- Fac2     
b29 Smoking <--- Fac2       
b32 Devices <--- Fac3       
b36 Comics <--- Fac3        
e01 NetShop <--> NetShop    
e02 Devices <--> Devices    
e03 SNS <--> SNS            
e04 Books <--> Books        
e05 Library <--> Library    
e06 Comics <--> Comics      
e07 NewsPaper <--> NewsPaper
e08 Volunteer <--> Volunteer
e09 Smoking <--> Smoking    
d01 Fac1 <--> Fac1          
d02 Fac2 <--> Fac2          
d03 Fac3 <--> Fac3          
b11 NetShop <--- Fac1       
r13 Fac3 <--> Fac1          
b21 Volunteer <--- Fac2     

 Iterations =  202 

 SNSの分散が負になったままであるので本来は良い分析結果ではない(不適解)が,例示なのでこれ以上のモデルの検討は省略する。

 構造方程式モデリングと云えばパス・ダイアグラムと云うイメージがあるので,取り敢えず簡単なグラフを描画する方法を紹介する。

DiagrammeR::pathDiagram(result03, edge.labels = "values")

パス・ダイアグラム

 次の様に,図の調整の為のオプションを幾つか付けると見た目を調整できる。

sem::pathDiagram(result03, 
                 ignore.double = FALSE, edge.labels = "values",
                 digits = 3,
                 node.font = c("Times New Roman", 10),
                 edge.font = c("Times New Roman", 10),
                 min.rank = "Devices", max.rank = "Books",
                 rank.direction = "TB",
                 same.rank = c("Fac1, Fac2, Fac3",
                               "SNS, Devices, NetShop, Comics, Smoking",
                               "Books, Library, NewsPaper, Volunteer"))

パス・ダイアグラム2
sem::stdCoef(result03)
> sem::stdCoef(result03)
       Std. Estimate                         
1         0.11755071        Devices <--- Fac1
2  b13    1.63502682            SNS <--- Fac1
3  b16    0.08234829      Volunteer <--- Fac1
4         0.56501774          Books <--- Fac2
5  b25    0.43874020        Library <--- Fac2
6  b27    0.32983733      NewsPaper <--- Fac2
7  b29   -0.29635769        Smoking <--- Fac2
8         0.39074681        NetShop <--- Fac3
9  b32    0.72527471        Devices <--- Fac3
10 b36    0.23888016         Comics <--- Fac3
11 e01    0.82027550     NetShop <--> NetShop
12 e02    0.42898719     Devices <--> Devices
13 e03   -1.67331269             SNS <--> SNS
14 e04    0.68075496         Books <--> Books
15 e05    0.80750703     Library <--> Library
16 e06    0.94293627       Comics <--> Comics
17 e07    0.89120733 NewsPaper <--> NewsPaper
18 e08    0.85977484 Volunteer <--> Volunteer
19 e09    0.91217212     Smoking <--> Smoking
20 d01    1.00000000           Fac1 <--> Fac1
21 d02    1.00000000           Fac2 <--> Fac2
22 d03    1.00000000           Fac3 <--> Fac3
23 b11    0.10785546        NetShop <--- Fac1
24 r13    0.18280850           Fac3 <--> Fac1
25 b21    0.36529977      Volunteer <--- Fac2
# cfaによるモデルの書き方
model.cfa <- sem::cfa(reference.indicators = TRUE,
    covs = "Fac1, Fac2, Fac3")
    Fac1: SNS, NetShop, Devices, Volunteer
    Fac2: Books, Library, NewsPaper, Volunteer, Smoking
    Fac3: NetShop, Devices, Comics

sem.cfa <- sem::sem(model.cfa, cor1, nrow(d11)) # 分析してオブジェクトに代入
summary(sem.cfa) # 結果の出力
sem::stdCoef(sem.cfa) # 標準化解を求める。
> model.cfa <- sem::cfa(reference.indicators = TRUE,
+                       covs = "Fac1, Fac2, Fac3")
1: Fac1: SNS, NetShop, Devices, Volunteer
2: Fac2: Books, Library, NewsPaper, Volunteer, Smoking
3: Fac3: NetShop, Devices, Comics
4: 
Read 3 items
NOTE: adding 9 variances to the model
> sem.cfa <- sem::sem(model.cfa, cor1, nrow(d11)) # 分析してオブジェクトに代入
Warning in eval(substitute(expr), data, enclos = parent.frame()) :
  Negative parameter variances.
Model may be underidentified.
> summary(sem.cfa) # 結果の出力

 Model Chisquare =  42.95241   Df =  21 Pr(>Chisq) = 0.00318767
 Goodness-of-fit index =  0.9767066
 Adjusted goodness-of-fit index =  0.9500856
 RMSEA index =  0.05301027   90% CI: (0.02987317, 0.07563674)
 AIC =  90.95241
 BIC =  -81.40073

 Normalized Residuals
      Min.    1st Qu.     Median       Mean    3rd Qu.       Max. 
-2.650e+00 -6.223e-01  2.000e-08 -1.309e-01  4.195e-01  2.293e+00 

 R-square for Endogenous Variables
      SNS   NetShop   Devices Volunteer     Books   Library NewsPaper 
  13.6916    0.2010    0.5066    0.1269    0.3091    0.2028    0.1013 
  Smoking    Comics 
   0.0929    0.0598 

 Parameter Estimates
                    Estimate     Std Error    z value     Pr(>|z|)    
lam[NetShop:Fac1]     0.01171545   0.12854750  0.09113715 9.273836e-01
lam[Devices:Fac1]     0.01360599   0.14984033  0.09080329 9.276489e-01
lam[Volunteer:Fac1]   0.01061099   0.11625152  0.09127612 9.272732e-01
lam[Library:Fac2]     0.81005157   0.19444950  4.16587121 3.101658e-05
lam[NewsPaper:Fac2]   0.57251542   0.15962104  3.58671657 3.348680e-04
lam[Volunteer:Fac2]   0.63807327   0.16895665  3.77655016 1.590155e-04
lam[Smoking:Fac2]    -0.54830391   0.15706045 -3.49103740 4.811489e-04
lam[Devices:Fac3]     1.59472385   0.74006896  2.15483143 3.117503e-02
lam[Comics:Fac3]      0.55279146   0.20123448  2.74700175 6.014281e-03
V[Fac1]              13.69163965 147.83891202  0.09261188 9.262119e-01
V[Fac2]               0.30908125   0.09005550  3.43211970 5.988832e-04
V[Fac3]               0.19585127   0.11178839  1.75198211 7.977688e-02
C[Fac1,Fac2]         -0.03607764   0.04179876 -0.86312699 3.880677e-01
C[Fac1,Fac3]          0.13781620   0.09189431  1.49972504 1.336856e-01
C[Fac2,Fac3]          0.02257408   0.02533318  0.89108746 3.728822e-01
V[SNS]              -12.69163966 147.84475151 -0.08584437 9.315901e-01
V[NetShop]            0.79904037   0.10718267  7.45493991 8.990880e-14
V[Devices]            0.49340672   0.23067576  2.13896221 3.243873e-02
V[Volunteer]          0.87310838   0.07574369 11.52714356 9.628557e-31
V[Books]              0.69091875   0.08869411  7.78990546 6.705935e-15
V[Library]            0.79718597   0.07793030 10.22947344 1.463127e-24
V[NewsPaper]          0.89869123   0.07370921 12.19238721 3.412754e-34
V[Smoking]            0.90707869   0.07357798 12.32812623 6.391574e-35
V[Comics]             0.94015208   0.07447253 12.62414523 1.554199e-36
                                            
lam[NetShop:Fac1]   NetShop <--- Fac1       
lam[Devices:Fac1]   Devices <--- Fac1       
lam[Volunteer:Fac1] Volunteer <--- Fac1     
lam[Library:Fac2]   Library <--- Fac2       
lam[NewsPaper:Fac2] NewsPaper <--- Fac2     
lam[Volunteer:Fac2] Volunteer <--- Fac2     
lam[Smoking:Fac2]   Smoking <--- Fac2       
lam[Devices:Fac3]   Devices <--- Fac3       
lam[Comics:Fac3]    Comics <--- Fac3        
V[Fac1]             Fac1 <--> Fac1          
V[Fac2]             Fac2 <--> Fac2          
V[Fac3]             Fac3 <--> Fac3          
C[Fac1,Fac2]        Fac2 <--> Fac1          
C[Fac1,Fac3]        Fac3 <--> Fac1          
C[Fac2,Fac3]        Fac3 <--> Fac2          
V[SNS]              SNS <--> SNS            
V[NetShop]          NetShop <--> NetShop    
V[Devices]          Devices <--> Devices    
V[Volunteer]        Volunteer <--> Volunteer
V[Books]            Books <--> Books        
V[Library]          Library <--> Library    
V[NewsPaper]        NewsPaper <--> NewsPaper
V[Smoking]          Smoking <--> Smoking    
V[Comics]           Comics <--> Comics      

 Iterations =  150 
> sem::stdCoef(sem.cfa) # 標準化解を求める。
                       Std. Estimate                         
1                         3.70022158            SNS <--- Fac1
2    lam[NetShop:Fac1]    0.04334977        NetShop <--- Fac1
3    lam[Devices:Fac1]    0.05034519        Devices <--- Fac1
4  lam[Volunteer:Fac1]    0.03926301      Volunteer <--- Fac1
5                         0.55595076          Books <--- Fac2
6    lam[Library:Fac2]    0.45034879        Library <--- Fac2
7  lam[NewsPaper:Fac2]    0.31829038      NewsPaper <--- Fac2
8  lam[Volunteer:Fac2]    0.35473732      Volunteer <--- Fac2
9    lam[Smoking:Fac2]   -0.30482998        Smoking <--- Fac2
10                        0.44255086        NetShop <--- Fac3
11   lam[Devices:Fac3]    0.70574642        Devices <--- Fac3
12    lam[Comics:Fac3]    0.24463834         Comics <--- Fac3
13             V[Fac1]    1.00000000           Fac1 <--> Fac1
14             V[Fac2]    1.00000000           Fac2 <--> Fac2
15             V[Fac3]    1.00000000           Fac3 <--> Fac3
16        C[Fac1,Fac2]   -0.01753776           Fac2 <--> Fac1
17        C[Fac1,Fac3]    0.08416070           Fac3 <--> Fac1
18        C[Fac2,Fac3]    0.09175093           Fac3 <--> Fac2
19              V[SNS]  -12.69163971             SNS <--> SNS
20          V[NetShop]    0.79904037     NetShop <--> NetShop
21          V[Devices]    0.49340673     Devices <--> Devices
22        V[Volunteer]    0.87310838 Volunteer <--> Volunteer
23            V[Books]    0.69091875         Books <--> Books
24          V[Library]    0.79718597     Library <--> Library
25        V[NewsPaper]    0.89869123 NewsPaper <--> NewsPaper
26          V[Smoking]    0.90707869     Smoking <--> Smoking
27           V[Comics]    0.94015208       Comics <--> Comics

発展1-2 構造方程式モデリングとパス解析(path analysis)

 男性に限定した完備ケース分析にて,年齢で教育年数を説明し,年齢と教育年数で収入を説明する(古典的)パス解析を行う17

# 各変数を男性に限定し,完備ケース分析とする
full.12 <- with(d01, complete.cases(age, edu, income))

d01m <- d01[full.12 & d01$sex == 1, c("age", "edu", "income")]

OLS1 <- lm(scale(edu) ~ scale(age), d01m)
OLS2 <- lm(scale(income) ~ scale(age) + scale(edu), d01m)
summary(OLS1); summary(OLS2)

Call:
lm(formula = scale(edu) ~ scale(age), data = d01m)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.4474 -0.7772  0.1277  0.8415  1.9028 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.862e-16  8.160e-02   0.000  1.00000    
scale(age)  -2.851e-01  8.189e-02  -3.481  0.00067 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.962 on 137 degrees of freedom
Multiple R-squared:  0.08127,   Adjusted R-squared:  0.07456 
F-statistic: 12.12 on 1 and 137 DF,  p-value: 0.0006701

Call:
lm(formula = scale(income) ~ scale(age) + scale(edu), data = d01m)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.3536 -0.5575 -0.0803  0.3794  5.1556 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -2.292e-16  8.016e-02   0.000 1.000000    
scale(age)   2.444e-01  8.394e-02   2.912 0.004204 ** 
scale(edu)   3.242e-01  8.394e-02   3.863 0.000173 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.9451 on 136 degrees of freedom
Multiple R-squared:  0.1197,    Adjusted R-squared:  0.1067 
F-statistic: 9.245 on 2 and 136 DF,  p-value: 0.000172
DiagrammeRによるPCA作図
grViz("
digraph classic_path {
  rankdir = LR;
  node [fontname = 'MS UI Gothic', 
        fontsize = 12,
        fillcolor = 'transparent',
        shape = box,
        style = filled];
  edge [fontname = 'Times-Roman', fontsize = 11];
  center = 1;
  {rank = min '年齢'}
  {rank = max '年収'}
  '教育年数' [fillcolor = 'transparent']
  '年収' [fillcolor = 'transparent']
  '年齢' -> '教育年数' [label = '-0.285**', color = black, penwidth = 1.00];
  '年齢' -> '年収' [label = '0.244**', color = black, penwidth = 1.001];
  '教育年数' -> '年収' [label = '0.324**', color = black, penwidth = 1.00];
  '教育年数' -> '教育年数' [headlabel = 'R2=.081', dir = none,
                            color = black, penwidth = 1.00, color = white];
  '年収' -> '年収' [headlabel = 'R2=.120', dir = none, color = black,
                    penwidth = 1.00, color = white];
 fontname = 'MS UI Gothic';
 fontsize = 11;
 labelloc = 't';
 label = 'lm()関数による古典的パス解析';
 }
      ")

 このパス解析を,SEMを使って実行してみよう。

n1   <- nrow(d01m) # SEMの為にケース数を保存
cor2 <- cor(d01m) # SEMの為に相関係数行列を保存

pathE <- sem::specifyEquations() # 記法その1
    edu = b12 * age
    income = b13 * age + b23 * edu
    V(age) = e1
    V(edu) = e2
    V(income) = e3

pathM <- sem::specifyModel() # 記法その2
    age -> edu, b12, NA
    age -> income, b13, NA
    edu -> income, b23, NA
    age <-> age, e1, NA
    edu <-> edu, e2, NA
    income <-> income, e3, NA

print(pathE) # 結果の同一性の確認
print(pathM)

 こうして記述したモデルをsem::sem( )関数に与えて構造方程式モデリングの分析を行う。pathEの部分をpathMとしても全く同一の出力である。

resultE <- sem::sem(pathE, cor2, N = n1)
summary(resultE)
> summary(resultE)

 Model Chisquare =  -2.298162e-14   Df =  0 Pr(>Chisq) = NA
 Goodness-of-fit index =  1
 AIC =  12
 BIC =  -2.298162e-14

 Normalized Residuals
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
0.000e+00 0.000e+00 0.000e+00 1.404e-16 0.000e+00 6.320e-16 

 R-square for Endogenous Variables
   edu income 
0.0813 0.1197 

 Parameter Estimates
    Estimate   Std Error  z value   Pr(>|z|)                       
b12 -0.2850766 0.08159334 -3.493871 4.760707e-04 edu <--- age      
b13  0.2443898 0.08332705  2.932899 3.358133e-03 income <--- age   
b23  0.3242468 0.08332705  3.891255 9.972694e-05 income <--- edu   
e1   1.0000000 0.12038585  8.306624 9.846344e-17 age <--> age      
e2   0.9187313 0.11060225  8.306624 9.846344e-17 edu <--> edu      
e3   0.8803181 0.10597784  8.306624 9.846344e-17 income <--> income

 Iterations =  0 

Footnotes

  1. 旧版のサポートウェブからスクリプトの書き方を一新しました。↩︎

  2. こうした処理は,標準関数だけでも十分に分かり易く行える。↩︎

  3. 標準化の関数が scale( )であったことを思い出そう。↩︎

  4. scale = Fが分散共分散行列の固有値分解に,scale = Tが相関係数行列の固有値分解に対応する。↩︎

  5. 70%に達するには第5主成分まで,約80%になるには第6主成分まで必要となる。↩︎

  6. ここではfont size(cex)を小さくし,かつcolorを薄いグレーにして目立たなくしている。↩︎

  7. もしかしたら年齢や性別を反映しているのかもしれない。↩︎

  8. 独自因子(=誤差; error)は e1 と表記し,○も□もつけない事とする。↩︎

  9. 計算結果やグラフは主成分分析と同じである。↩︎

  10. インストールしたら,library(psych)としてパッケイジを有効化するか,或いは以下の様にダブルコロンを用いてパッケイジの中の特定の関数だけを呼び出す。↩︎

  11. fa = オプションでpc(principal components), fa(principal axis factor analysis), bothを指定できる。↩︎

  12. 上の分析結果の中に現れているものと一致している。↩︎

  13. 後述するが,回転法はPromaxとしている。↩︎

  14. The default is to do a oblimin transformation, although versions prior to 2009 defaulted to varimax. SPSS seems to do a Kaiser normalization before doing Promax, this is done here by the call to “promax” which does the normalization before calling Promax in GPArotation.↩︎

  15. この計算方法は,SPSSのプロマックス解と一致するタイプのものである。↩︎

  16. ここから先は,RStudio上のQuartoと相性が悪いのか実行されなかったので,別途実行して出力した結果を貼り付けている。↩︎

  17. ここも旧版サポートウェブからスクリプトの書き方を大きく変えている。↩︎