井出草平の研究ノート

sem関数とlavaan関数[R]

sem関数が自働的にコードを補ってくれるため、基本的な分析には適しているが、細かいところまでコードを書き込む場合には、lavaan関数の方が向いていることもある。

sem関数での推定

PoliticalDemocracyを使って簡単なSEMを作成してみる。以下のようなSEMである。

f:id:iDES:20200726003103p:plain

x1 1960年の一人当たり国民総生産(GNP)
x2 1960年の一人当たりの無生物エネルギー消費量
x3 1960年の産業界における労働力の割合

y1 1960年の報道の自由に関する専門家の評価
y2 1960年の政治的反対運動の自由
y3 1960年の選挙の公平性
y4 1960年の選出立法府の有効性

library(lavaan)
## model
model <- '
  # measurement model
    ind60 =~ x1 + x2 + x3
    dem60 =~ y1 + y2 + y3 + y4
    
  # regressions
    dem60 ~ ind60 '
fit <- sem(model=model, data=PoliticalDemocracy)
summary(fit, standardized=TRUE) 

自働で設定されている項目

sem関数はすべてを書かなくてもコードは走るようになっている。自働的にコードを補ってくれているからである。このことを確認するのはparTable関数を使う。

parTable(fit)
   id   lhs op   rhs user block group free ustart exo label plabel start   est
1   1 ind60 =~    x1    1     1     1    0      1   0         .p1. 1.000 1.000
2   2 ind60 =~    x2    1     1     1    1     NA   0         .p2. 2.193 2.180
3   3 ind60 =~    x3    1     1     1    2     NA   0         .p3. 1.824 1.818
4   4 dem60 =~    y1    1     1     1    0      1   0         .p4. 1.000 1.000
5   5 dem60 =~    y2    1     1     1    3     NA   0         .p5. 1.296 1.419
6   6 dem60 =~    y3    1     1     1    4     NA   0         .p6. 1.055 1.095
7   7 dem60 =~    y4    1     1     1    5     NA   0         .p7. 1.294 1.428
8   8 dem60  ~ ind60    1     1     1    6     NA   0         .p8. 0.000 1.439
9   9    x1 ~~    x1    0     1     1    7     NA   0         .p9. 0.265 0.081
10 10    x2 ~~    x2    0     1     1    8     NA   0        .p10. 1.126 0.120
11 11    x3 ~~    x3    0     1     1    9     NA   0        .p11. 0.975 0.467
12 12    y1 ~~    y1    0     1     1   10     NA   0        .p12. 3.393 2.404
13 13    y2 ~~    y2    0     1     1   11     NA   0        .p13. 7.686 6.552
14 14    y3 ~~    y3    0     1     1   12     NA   0        .p14. 5.310 5.363
15 15    y4 ~~    y4    0     1     1   13     NA   0        .p15. 5.535 2.137
16 16 ind60 ~~ ind60    0     1     1   14     NA   0        .p16. 0.050 0.449
17 17 dem60 ~~ dem60    0     1     1   15     NA   0        .p17. 0.050 3.453

freeの項目で0がふられているのは固定母数である。free0だとustart列で1の値となっている。 1~8行目はモデルに書き込んだものだが、9~17行目は自働で補足された部分である。

lavaan関数

sem関数で自働的に書かれたコードをフルで書くのがlavaan関数である。利点は細かいところまで設定できるところである。
さて、さきほどのsem関数に入れたモデルをlavaan関数で走らせるには以下のように書く。

## model
model2 <- '
  # measurement model
    ind60 =~ 1*x1 + x2 + x3
    dem60 =~ 1*y1 + y2 + y3 + y4
    
  # regressions
    dem60 ~ ind60

  # Variances
    x1 ~~ x1
    x2 ~~ x2
    x3 ~~ x3
    y1 ~~ y1
    y2 ~~ y2
    y3 ~~ y3
    y4 ~~ y4
    ind60 ~~ ind60
    dem60 ~~ dem60 '

freeの項目で0が降られたところに1*を足して固定母数を表現する。あとは分散を書き入れれば、このモデルは完成である。

fit2 <- lavaan(model=model2, data=PoliticalDemocracy)
summary(fit2, standardized=TRUE) 

lavaan関数を利用すると、例えば固定母数を変更することができる。

sem関数とlavaan関数の違いは下記の5点である。

  • 観測変数の誤差分散と潜在変数の分散を推定する。(auto.var)
  • 外生的な潜在変数聞の共分散を推定する。(auto.cov.lv.x)
  • 観測変数と潜在変数両者の内生的な変数聞の共分散を推定する。(auto.cov.y)
  • 最初の指標の因子負荷を1に固定する(std.lv=TRUEではないとき)。(auto.fix.first)
  • 指標が1つのときに誤差分散を0に固定する。(auto.fix.single)

lavaan関数でもこの5つのオプションをTRUEにすると、sem関数と同じになる。

semPlot

library(semPlot)
semPaths(fit, layout = "tree", shapeLat="ellipse", whatLabels  = "stand", 
         nDigits=3, shapeMan="square", sizeMan =8, 
         sizeLat =8, sizeLat2 =8, style = "lisrel",
         residScale=12, curve=2.5, optimizeLatRes=T,edge.color="black",
         rotation = 2, edge.label.cex=1)