野球のデータ,baseball2015.csvをb.dataというオブジェクトに入れているとします。 できてないひとは,次の通りやってみよう。
b.data <- read.csv("baseball2015.csv",na.strings="*")
回帰分析とは,\[y=a_1 x_1+a_2 x_2+...+b\] という線形関数を当てはめることでした。 たとえば,年齢を身長と体重で予測するとしたら,次のようになります。
reg1 <- lm(age~height+weight,data=b.data)
summary(reg1)
##
## Call:
## lm(formula = age ~ height + weight, data = b.data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -9.8751 -2.5722 -0.0974 2.7866 14.2368
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 54.30186 10.24212 5.302 3.06e-07 ***
## height -0.18010 0.06869 -2.622 0.00943 **
## weight 0.11466 0.03956 2.898 0.00418 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.373 on 197 degrees of freedom
## Multiple R-squared: 0.04348, Adjusted R-squared: 0.03377
## F-statistic: 4.478 on 2 and 197 DF, p-value: 0.01254
回帰分析の説明変数が名義尺度水準である場合,このモデルは分散分析とおなじことになります。このように,分散分析(やt検定)と重回帰分析をまとめて一般に一般線形モデルと言います。
確認してみましょう。従属変数は身長だとして,投げる手(throw)を説明変数にすると,次のようになります。
str(b.data$throw) # throw変数はfactor型になっていることに注意!
## Factor w/ 2 levels "右","左": 2 1 2 1 1 1 2 1 1 2 ...
reg2 <- lm(height~throw,data=b.data)
summary(reg2)
##
## Call:
## lm(formula = height ~ throw, data = b.data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -15.205 -4.205 -1.205 2.795 22.795
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 182.2047 0.5031 362.183 <2e-16 ***
## throw左 -1.6185 1.3211 -1.225 0.222
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.579 on 198 degrees of freedom
## Multiple R-squared: 0.007523, Adjusted R-squared: 0.00251
## F-statistic: 1.501 on 1 and 198 DF, p-value: 0.222
ここで,説明変数に「throw左」とあるのは,throw右(1)にくらべて,左(2)になるとどれぐらい従属変数が上がるか,ということを表しています。そして係数が有意で無い=傾きが0であるという帰無仮説を棄却できないので,利き手によって身長に差は無い,ということがわかります(これは全く面白くない仮説でしたし!)
これの別表現がt検定ですね。
reg2t <- t.test(height~throw,data=b.data)
回帰分析と同じ表現ができていることに注目してください。
同様に,血液型など2水準以上のデータであっても検証できます。
str(b.data$blood) # factor型になっていることを確認
## Factor w/ 5 levels "AB型","A型","B型",..: 2 4 2 4 3 4 2 3 2 1 ...
reg3 <- lm(height ~ blood,data=b.data)
summary(reg3)
##
## Call:
## lm(formula = height ~ blood, data = b.data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -14.0667 -3.3875 -0.3833 2.8437 18.6167
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 179.8462 1.4967 120.160 < 2e-16 ***
## bloodA型 -0.4628 1.6509 -0.280 0.780
## bloodB型 0.3101 1.7749 0.175 0.861
## bloodO型 0.5538 1.6801 0.330 0.742
## blood不明 9.2205 1.6992 5.426 1.69e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 5.397 on 195 degrees of freedom
## Multiple R-squared: 0.3423, Adjusted R-squared: 0.3288
## F-statistic: 25.37 on 4 and 195 DF, p-value: < 2.2e-16
reg3anova <- aov(height~blood,data=b.data)
summary(reg3anova)
## Df Sum Sq Mean Sq F value Pr(>F)
## blood 4 2955 738.7 25.37 <2e-16 ***
## Residuals 195 5679 29.1
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
回帰分析と同じ数字がでていることを確認しましょう。
重回帰分析は変数Aで変数Bを予測する,という方法ですから,この連鎖をつなげて変数Aが変数Bを,変数Bが変数Cを,変数Cが変数Dを・・・と繋がっていくと「影響力の伝播」を検証できます。 この方法を,パス解析と言います。
例として,年収が体重を,体重が身長を予測するパス解析をやってみましょう。
path1.1 <- lm(weight ~ pay,data=b.data)
path1.2 <- lm(height ~ weight,data=b.data)
summary(path1.1)
##
## Call:
## lm(formula = weight ~ pay, data = b.data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -21.950 -7.269 -1.624 6.427 35.376
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.517e+01 1.320e+00 64.513 < 2e-16 ***
## pay 2.364e-04 7.843e-05 3.014 0.00291 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 11.21 on 198 degrees of freedom
## Multiple R-squared: 0.04387, Adjusted R-squared: 0.03905
## F-statistic: 9.086 on 1 and 198 DF, p-value: 0.002913
summary(path1.2)
##
## Call:
## lm(formula = height ~ weight, data = b.data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -12.6964 -2.7573 -0.3232 2.3683 16.1768
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 144.90581 2.49850 58.00 <2e-16 ***
## weight 0.41952 0.02805 14.96 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.525 on 198 degrees of freedom
## Multiple R-squared: 0.5305, Adjusted R-squared: 0.5281
## F-statistic: 223.7 on 1 and 198 DF, p-value: < 2.2e-16
このモデルの背景には,「年収が増えると美味しいものを食べれるから,体重が大きくなるだろう。体重が大きくなったら,足の裏にもお肉がつくから,身長だって伸びるだろう」というストーリー(仮説)があります。
パス解析では,まず仮説がないと分析になりませんし,モデルが当てはまっていても(モデル適合度は\(R^2\)でした),仮説が実質的に妥当なものでなければ意味がありません。
今回の仮説は,実質的には多少馬鹿馬鹿しいものでしたし,モデルの適合度もよくありませんでしたね。これは悪い例です。みなさんは良い仮説のもと,データに基づいたモデリングを進めてください。
パス解析のパスはいくら長くなっても構いませんが,そのたびに回帰分析をやっていくのは面倒です。また,先ほどの例ではPath1.2の適合度はそこそこよかった(\(R^2=0.53\))のですが,Path1.1の適合度はわるかった(\(R^2=0.04\))ですね。この場合,「モデル全体としては,結局よかったの,悪かったの?」ということがはっきりしません。
また,一つのデータに対して,複数のモデルを当てはめることで,一部の変数(体重)が重複して使われることになってしまいました。これはデータの水増しをしているようで,あまり良いことではありません。
こうした問題を解決する手法が構造方程式モデリング(SEM)です。SEMでは,
というメリットがあります。
SEMをRで行う一つの方法は,lavaanパッケージを使うことです。
# install.packages("lavaan") # パッケージが無い場合はインストールをしておく
library(lavaan)
## Warning: package 'lavaan' was built under R version 3.2.2
## This is lavaan 0.5-19
## lavaan is BETA software! Please report any bugs.
# モデルが複数行にわたっていることに注意
model <- '
weight ~ pay
height ~ weight
'
result.path <- sem(model,data=b.data)
summary(result.path,standardized=T,fit.measure=T)
## lavaan (0.5-19) converged normally after 17 iterations
##
## Number of observations 200
##
## Estimator ML
## Minimum Function Test Statistic 1.759
## Degrees of freedom 1
## P-value (Chi-square) 0.185
##
## Model test baseline model:
##
## Minimum Function Test Statistic 161.953
## Degrees of freedom 3
## P-value 0.000
##
## User model versus baseline model:
##
## Comparative Fit Index (CFI) 0.995
## Tucker-Lewis Index (TLI) 0.986
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -3478.834
## Loglikelihood unrestricted model (H1) -3477.955
##
## Number of free parameters 4
## Akaike (AIC) 6965.668
## Bayesian (BIC) 6978.861
## Sample-size adjusted Bayesian (BIC) 6966.189
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.062
## 90 Percent Confidence Interval 0.000 0.210
## P-value RMSEA <= 0.05 0.289
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.026
##
## Parameter Estimates:
##
## Information Expected
## Standard Errors Standard
##
## Regressions:
## Estimate Std.Err Z-value P(>|z|) Std.lv
## weight ~
## pay 0.000 0.000 3.029 0.002 0.000
## height ~
## weight 0.420 0.028 15.033 0.000 0.420
## Std.all
##
## 0.209
##
## 0.728
##
## Variances:
## Estimate Std.Err Z-value P(>|z|) Std.lv
## weight 124.418 12.442 10.000 0.000 124.418
## height 20.268 2.027 10.000 0.000 20.268
## Std.all
## 0.956
## 0.469
回帰分析のときに示された数値に該当するところがどこに出力されているか,見つけておきましょう。ちなみに,回帰分析の推定法(最小二乗法,LS)とちがって,最尤推定法(Maximum Likelihood,LM法)になっているので少し違うことがあります。
さて,出力(summary)の際に二つオプションをつけました。
適合度指標はこのモデルに全体に対して出力されますが,異なる観点から複数の指標が算出されるので,それらを見て総合的に判断します。
適合度 | 基準 |
---|---|
CFI | 0.9以上なら良いモデル |
TLI | 0.9以上なら良いモデル |
AIC | 同じデータセットなら小さいほど良いモデル |
BIC | 同じデータセットなら小さいほど良いモデル |
RMSEA | 0.05以下なら良いモデル |
SRMR | 0.05以下なら良いモデル |
パス解析は,結果を図にして表現するのが一般的です。その方がわかりやすいもんね。 基本的には左から右に,影響力が伝播していくように記載します。 semPlotパッケージを使うと,パス図を自動的に描いてくれるので便利です。
library(semPlot)
## Warning: package 'semPlot' was built under R version 3.2.2
semPaths(result.path,what="stand",style="lisrel")
仮説の妥当性,モデルの適合度も評価対象です。良いモデルを作ってくださいね。