重回帰分析で単純傾斜を検討するときの個人的な理解の仕方
1 この資料の目的
この資料は,重回帰分析の単純傾斜を検討するときにする変数処理の理屈について,個人的な理解を,統計ソフトのRを使ってデータと照らし合わせながらまとめたものです。以下,なんでこんなものを作ったのかの理由です。
重回帰分析で交互作用の影響を検討するとき,交互作用項を作って重回帰モデルに入れると思います。多くの場合,交互作用項の影響が有意であれば,次に下位検定である単純傾斜(simple slope)の影響を検討をしていきます。
単純主効果を検討するときに,量的変数の調整変数が高い時と低い時の変数を作って,それぞれ検討します。その際,もとの値から-1SDした調整変数の値を調整変数が高い時,もとの値から+1SDした調整変数の値を調整変数が低い時とするのが通例と思います(Rを使った具体的な実行方法だと,例えば広島大学の平川さんの資料がシンプルにまとまっていてわかりやすいかと思います)。
このとき,素朴に感じる疑問は,なんで調整変数の高い時を検討するのに-1SDした変数を高い時の値として扱うのか,ということです。今までグラフの平行移動をイメージして,調整変数の高い場合を検討したいときにはプラス側に移動するから-1SD(実際?は-(+1SD))して,調整変数の低い場合を検討したいときにはマイナス側に移動するから+1SD(実際?は-(-1SD))するという理解でした。でもこれが何でなのか,友人に聞かれた際に明確に答えられなかったので,自分の理解の仕方をまとめてみようと思って作ってみた次第です。
私はあまり数学的な素養がないので,実際のデータと照らし合わせながら理解することを目指します。以下では,Rを使ってやっている処理を可視化しながら説明をしてみます。
2 使うデータについて
データは関西学院大学の清水先生のブログからもってきました。詳細も書かれています。以下の3つの変数を関係を検討します。
y(従属変数): 満足度(sat)
x(説明変数): 話す頻度(talk)
z(調整変数): パフォーマンス(per)
## Parsed with column specification:
## cols(
## group = col_double(),
## sat = col_double(),
## talk = col_double(),
## per = col_double(),
## con = col_double()
## )
dat01としてサンプルデータを読み込みます。データフレームの上からいくつかのデータを見てみるとこんな感じです。
group | sat | talk | per | con |
---|---|---|---|---|
1 | 3 | 3 | 3 | 1 |
1 | 3 | 2 | 3 | 1 |
1 | 3 | 3 | 3 | 1 |
2 | 3 | 3 | 3 | 0 |
2 | 2 | 1 | 3 | 0 |
2 | 2 | 1 | 3 | 0 |
とりあえず,可視化してみます。
見た感じ,色の濃いのが右肩下がりで色の薄いのが右肩上がりな様子。 もう少しわかりやすくするために,次は,パフォーマンス(per)の高群と低群のみのデータで描いてみる。なお,今回は高群を1, 低群を0, 中間を2とコーディングしています。
群分けしたときのそれぞれの人数の確認をしてみます。Var1っていうのが群分けの変数です。Freqは人数です。
Var1 | Freq |
---|---|
0 | 42 |
1 | 42 |
2 | 216 |
高低群のみをグラフにして,それぞれの群の回帰直線をかいてやるとわかりやすいかもしれません。
交互作用有りっぽい図が描けました。こういう結果(高群は回帰係数が正,低群は回帰係数が0か負)に近い分析結果ならokだと考えられます。
3 回帰分析して手順の正しさを確認
交互作用が有意なことを確認(talkとperは中心化した変数を使用している)。jtoolパッケージが良さげだと聞いたのでsummary()ではなくsumm()で結果をみています。
## MODEL INFO:
## Observations: 300
## Dependent Variable: sat
## Type: OLS linear regression
##
## MODEL FIT:
## F(3,296) = 27.58, p = 0.00
## R2 = 0.22
## Adj. R2 = 0.21
##
## Standard errors: OLS
## ------------------------------------------------
## Est. S.E. t val. p
## ------------------ ------ ------ -------- ------
## (Intercept) 3.42 0.05 66.77 0.00
## talk_c 0.27 0.05 5.12 0.00
## per_c 0.14 0.03 4.78 0.00
## talk_c:per_c 0.13 0.03 4.29 0.00
## ------------------------------------------------
次に確認。高群は−1SD,低群は+1SDした推定値が最初に可視化したものと似るはず。答えが正しいことの確認をしてから説明に入ります。
コードを見てもらえばわかると思いますが,高群を作るときに,perを−1SDしてます。talkの変数は中心化したものを使っています。
## MODEL INFO:
## Observations: 300
## Dependent Variable: sat
## Type: OLS linear regression
##
## MODEL FIT:
## F(3,296) = 27.58, p = 0.00
## R2 = 0.22
## Adj. R2 = 0.21
##
## Standard errors: OLS
## ---------------------------------------------------
## Est. S.E. t val. p
## --------------------- ------ ------ -------- ------
## (Intercept) 3.66 0.07 50.15 0.00
## talk_c 0.49 0.07 6.98 0.00
## per_high 0.14 0.03 4.78 0.00
## talk_c:per_high 0.13 0.03 4.29 0.00
## ---------------------------------------------------
talkの回帰係数は.49
同じく中心化もして,perを+1SDしてます。
## MODEL INFO:
## Observations: 300
## Dependent Variable: sat
## Type: OLS linear regression
##
## MODEL FIT:
## F(3,296) = 27.58, p = 0.00
## R2 = 0.22
## Adj. R2 = 0.21
##
## Standard errors: OLS
## --------------------------------------------------
## Est. S.E. t val. p
## -------------------- ------ ------ -------- ------
## (Intercept) 3.17 0.07 43.81 0.00
## talk_c 0.04 0.08 0.48 0.63
## per_low 0.14 0.03 4.78 0.00
## talk_c:per_low 0.13 0.03 4.29 0.00
## --------------------------------------------------
talkの回帰係数は0.037で可視化したものに近くなりました。処理の仕方はこれで正しいと思われます。
jtoolパッケージ遊びのために,平均,高群,低群の結果をいろいろな形で見比べてもみます。
talk_cの効果だけ違うのがよくわかりやすい気がします。変数名を変えなければもっと見やすくはなるかもしれません。
Tableにもできるみたいだけど,別のパッケージが必要になるみたいなのでstargazerパッケージでさくっと結果をまとめてみます。
##
## Please cite as:
## Hlavac, Marek (2018). stargazer: Well-Formatted Regression and Summary Statistics Tables.
## R package version 5.2.2. https://CRAN.R-project.org/package=stargazer
Dependent variable: | |||
sat | |||
mean | high | low | |
(1) | (2) | (3) | |
talk_c | 0.266*** | 0.494*** | 0.037 |
(0.052) | (0.071) | (0.078) | |
per_c | 0.141*** | ||
(0.029) | |||
talk_c:per_c | 0.130*** | ||
(0.030) | |||
per_high | 0.141*** | ||
(0.029) | |||
talk_c:per_high | 0.130*** | ||
(0.030) | |||
per_low | 0.141*** | ||
(0.029) | |||
talk_c:per_low | 0.130*** | ||
(0.030) | |||
Constant | 3.416*** | 3.663*** | 3.170*** |
(0.051) | (0.073) | (0.072) | |
Observations | 300 | 300 | 300 |
R2 | 0.218 | 0.218 | 0.218 |
Adjusted R2 | 0.211 | 0.211 | 0.211 |
Residual Std. Error (df = 296) | 0.884 | 0.884 | 0.884 |
F Statistic (df = 3; 296) | 27.576*** | 27.576*** | 27.576*** |
Note: | p<0.1; p<0.05; p<0.01 |
4 交互作用項を含む重回帰分析における単純主効果の検討方法の意味
4.1 前提
Y=β頻度talk得点+βパフォーマンスper得点+β頻度∗パフォーマンスtalk得点∗per得点+切片
これをtalk得点について,まとめていくと
Y=(β頻度+β頻度∗パフォーマンスper得点)talk得点+βパフォーマンスper得点+切片
つまり,talk得点の傾きはper得点の値によって変化することがわかります。そして,per得点の高い時と低い時によってtalk得点の影響が変わってきます。慣例のAken & West(1991)あたりに従って,平均から1SD離れたあたりをとっています。
ちなみに,
Y=(β頻度+β頻度∗パフォーマンスper得点)talk得点+βパフォーマンスper得点+切片
に先ほどの最初に確かめた中心化した2つの変数を入れた重回帰分析の推定値とperの1SDの値を代入すると,+1SDを代入したときには,高群の回帰係数0.49,-1SDを代入したときには低群の回帰係数0.037と大体同じ推定値が得られることがわかります。こうして得られた推定値が有意か否かは,推定値の差分を使って求めることができます。詳細はRobinson, Tomek, & Schumacker(2013)PDF注意を参照ください。
## [1] 1.756184
ˆY=(0.27+0.13per得点)talk得点+0.14per得点+3.42
perのSDは1.76なので,高群の場合のtalkの回帰係数の推定値を求める場合は,上の式に1.76を代入します。
ˆY=(0.27+0.13×1.76)talk得点+0.14×1.76+3.42
ˆY=0.50talk得点+3.67
低群の場合は,-1.76を代入します。
ˆY=(0.27+0.13×(−1.76))talk得点+0.14×(−1.76)+3.42
ˆY=0.04talk得点+3.17
となり,回帰係数と切片の値は大体一致します。
4.2 なぜ単純傾斜を重回帰分析で検討するときは−1SDした変数を高群,+1SDした変数を低群として扱うのか
ようやく本題です。これ正確には高群では1SDを低群では-1SDを代入しています。なぜ以下では,なぜ符号が入れ替わるのかを説明するのを頑張ってみます。
例えば,前田(2008)でも書かれているように,
高群を検討する変数をつくるときは,
調整変数高群=調整変数−(1SD)
低群を検討する変数をつくるときは,
調整変数低群=調整変数−(−1SD)
という処理をしており,結果的に高群では-1SDして,低群では+1SDすることとなっています。
4.2.1 per得点が平均値のときを考える
ここで,全ての変数をセンタリングして解析したとすれば,per得点が平均値のときには(β頻度+β頻度∗パフォーマンス×0)talk得点となって交互作用項を考慮する必要がなくなります。もともとの重回帰分析の係数の解釈は,他の係数が0のときの効果であることも思い出しておきましょう。
今後のために,per得点を込みにした3次元で考えてみます。2次元のグラフはこれをtalk側から見て,per得点を考慮せずに見たものとなります(ブルドーザーで押しつぶす感じ。 perを周辺化する感じのイメージ)。
無理やり3Dプロットで考えると,緑のプロットの人たち(per=0(中心化しているので))のtalk回帰係数を意味します。普通の重回帰分析で出てくるtalkの回帰係数は,緑のプロットにおける回帰係数が推定されています。 交互作用が有意とはピンクや青のプロットの人たちは,緑のプロットの人たちとはtalkの回帰係数が異なることを意味するので,別途確認しなくてはいけません。
4.3 3D plotでper得点の高低がどの辺にあるかを考える
見辛いのでperの1SD以上と以下の人だけをプロットすると,ちゃんとper得点の高低で傾向の違う様子がわかります。
なお,これを2次元につぶすとこのように見えます(per次元をつぶす)
perが1SD高い状態をみるときには,実際にperが1SD高い人たちのデータのみを使うのではなく,perを1SD低い状態に全体的に動かすことで,対処しています。ここで思い出して欲しいのは,talkの回帰係数は,per=0かつper×talk=0のときの影響であり,センタリングをしている変数perc=0のときとは,perが平均値の時のことを意味しています。
今確認したいのは,per高群であり,平均よりも1SD高い時なので,per高群=0が1SD高い値となるような変数per高群を作ってあげる必要があります。
この3Dプロットでいうと,ピンク色のプロット(1SD高い状態)をper=0として,talkの回帰係数を考えられる状態をつくることを意味します。per高群=perc−1SDとすることで,平均値は,全体的に負方向に推移し,per高群=0のときには,実質的にper=1SDの状態を検討できます。そのため,percの値に1SD加算するのではなく,1SD減算する必要があります。
回帰分析において,調整変数が1SD分高い状態における説明変数と従属変数の関連を検討する際には,調整変数を+1SD高い状態が基準(調整変数の得点が0)となるようにした新たな変数調整変数高群を作成する必要がある。調整変数高群を作成する際には,1SD分加算するのではなく1SD減算する操作を加えることとなる。
同様に,1SD低い状態を考える時は,青色のプロット(1SD低い状態)をper低群=0として,talkの回帰係数を考えられるようにする必要があります。そのため,新たに作成する調整変数per低群はpercから1SD加算(正確には−1SD分を減算)する必要があります。
4.4 per高群,低群および平均値のデータセットの可視化(たぶん,こんがらがるポイント)
まずは,単純にperとsat(Y)の関連をみる。perは中心化してあります。黒い点や線が平均,赤い点や線が高群とされているもの(perc−1SD),青い点や線が低群とされているもの(perc−(−1SD))を示します。
g04 <- ggplot(dat01, aes(x = per_c, y = sat)) +
geom_jitter(height = 0.1, width = 0.4, colour = "black", alpha = 0.5) +
stat_smooth(method = "lm", colour = "black") + geom_jitter(aes(x = per_high, y = sat), height = 0.1, width = 0.4, colour = "red", alpha = 0.5) +
stat_smooth(aes(x = per_high, y = sat), method = "lm", colour = "red") +
geom_jitter(aes(x = per_low, y = sat), height = 0.1, width = 0.4, colour = "blue", alpha = 0.5) +
stat_smooth(aes(x = per_low, y = sat), method = "lm", colour = "blue") +
xlab("per_high(red), per_c(black), per_low(blue)")
g04
たぶん,高群なのに1SD引いて,低群なのに1SD足すの?って気になってしまう人のは,こんなグラフを思い浮かべているんだと思います。なぜ,結果的にpercの値を低くした変数をper高群といわれていて,percの値を高くするときにper低群といわれているのか,ということかなと。
上のグラフでも示されているが,以下のように平均値を算出するとperlowはperhighのよりも大きな値となっていることが確認できます。なぜperlowの値のほうがperhighよりも高い数値なのにperlowをpercの代わりに代入して重回帰分析したときには,低群の結果といえるのか,疑問に感じている,ということだと思います。
per | per_c | per_high | per_low |
---|---|---|---|
4.69 | 0 | -1.76 | 1.76 |
sat得点をtalkcとperhighおよびその交互作用を使って重回帰分析で予測することは,perhighについては赤い線の部分の回帰を行なっていることになります。
重回帰分析の回帰係数は,他の回帰係数が0だったときの回帰係数を推定するので,perhigh=0のときのtalkの回帰係数が推定されることとなります。perhighの平均値は0ではなく-1.76であり,perhigh=0とは,下の赤い散布図を見ればわかるようにパフォーマンス(per)が高い人たちであることがわかります。会話頻度(talk)の回帰係数は,percとは異なり,perhigh=0,つまりper=Mean+1SDのときの回帰係数を意味するようになります。そのため,perc−1SDがper高群とみなせます。
per低群=perc+1SDのときも同様に考えられます。perlowの平均値は0ではなく1.76であり,perlow=0とは,下の青い散布図を見ればわかるようにパフォーマンス(per)が低い人たちであることがわかります。会話頻度(talk)の回帰係数は,percとは異なり,perlow=0,つまりper=Mean−1SDのときの回帰係数を意味するようになります。そのため,perc+1SDがper低群とみなせます。
4.4.1 グラフの平行移動について
ここでは,なぜ高群のときに“調整変数を+1SD高い状態が基準(調整変数の得点が0)となるように平行移動させることを意味し,実際には調整変数に対して1SD分加算するのではなく1SD減算する操作を加える”,低群のときに“調整変数であるperを1SD加算(正確には−1SD分を減算)”と書いたか説明を試みます。蛇足かも。
基礎知識確認
y=xのグラフをx軸に沿ってa平行移動させるとy=x−aと表現できる。-a平行移動させる場合は,y=x−(−a)と表現できます。
例えば,以下に示すy=2xの緑のグラフをx軸方向に2平行移動させるとy=2(x−2)となり,赤のグラフ(y=2x−4)となる。y=2x−4はx=0のとき,y=−4となります。
次にy=2xの緑のグラフをx軸方向に-2平行移動させるとする。その場合,y=2(x−(−2))となり,青のグラフy=2x+4となる。y=2x+4はx=0のとき,y=4となります。
func <- function(x){2*x}
func_h <- function(x){2*x - 4}
func_l <- function(x){2*x + 4}
plot(func, -5, 5, col = "green")
plot(func_h, -5, 5, col = "blue", add = TRUE)
plot(func_l, -5, 5, col = "red", add = TRUE)
abline(v = 0, lty = 2, add =TRUE)
abline(h = 0, lty = 2, add =TRUE)
text(4, labels = "y = 2x + 4", col = "red")
text(0, labels = "y = 2x", col = "green")
text(-5, labels = "y = 2x - 4", col = "blue")
これをさきほどの重回帰分析(Y=β頻度talk得点+βパフォーマンスper得点+β頻度∗パフォーマンスtalk得点∗per得点+切片)の高群と低群を作る手続きに合わせてみると,
per高群を作るときは,緑のグラフを赤のグラフまで1SD平行移動することを意味します。per軸方向に1SD平行移動するため,1SD分減算します。こうすることで,talkの回帰係数は,per=0のとき実際にはper=1SDとして解釈できるようになります。
per低群を作るときは,緑のグラフを青のグラフの位置に移動させるように,per軸方向に-1SD平行移動させるため,1SD加算することにつながります。こうすることで,talkの回帰係数は,per=0のとき実際にはper=−1SDとして解釈できるようになります。
これで一応,なぜ高群を検討するときに−1SDし,低群を検討するときに+1SDするか理解できる(といいな)。
4.4.2 +1SDを検討するとき素直に加算するとどうなるか
気になったのでこれも検討してみる。これまでと基本的には同じことを試しているだけです。
xとyという2つの変数があったときに,xのSD=2だったとする。xとyの関係は緑のグラフに表します。
そうして,高群を検討したいから,単純に1SD分加算したもの(つまり,x+2)とyの関係を青のグラフに表すと以下のようになります。
先ほどのように考えてみると,緑のグラフから青のグラフへのx軸方向への移動は,−1SD分x軸方向に平行移動させたことを意味し,なんらかの変数と交互作用が有意であった場合,青のグラフの変数xの得点を使って重回帰分析にかけると,x=0のとき,xは−1SD分小さい値となり,もう一つの変数の回帰係数は,低群の効果を意味することになってしまいます。
5 まとめ
調整変数の高群,低群を作って再度重回帰分析で説明変数の変化を検討する場合,
高群にはセンタリングした調整変数に−1SDした変数を作成して,重回帰分析を行う。
低群にはセンタリングした調整変数に+1SDした変数を作成して,重回帰分析を行う。
符号が逆転する理由は,説明変数の回帰係数の解釈のさせ方を変えられるようにするためである。 *ie., 高群であれば,調整変数の全体の平均値を1SD低くしているため,調整変数が0のときの説明変数の回帰係数の解釈は,調整変数が1SD分の高いときの解釈となる。低群であれば,調整変数の全体の平均値を1SD高くしているため,調整変数が0のときの説明変数の回帰係数の解釈は,調整変数が1SD分の低いときの解釈となる。
ついでに,
- 重回帰式に代入して,説明変数の回帰係数を算出するとき:センタリングした変数を用いて推定された回帰係数を代入し,調整変数の得点には,高群のときには+1SDの値を,低群のときには-1SDの値を代入したら算出できる。ただし,それにくわえてプールされた標準誤差を算出して,回帰係数の差分の有意性検定を行うことになるっぽい。
6 実行環境
## R version 3.5.2 (2018-12-20)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 18362)
##
## Matrix products: default
##
## locale:
## [1] LC_COLLATE=Japanese_Japan.932 LC_CTYPE=Japanese_Japan.932
## [3] LC_MONETARY=Japanese_Japan.932 LC_NUMERIC=C
## [5] LC_TIME=Japanese_Japan.932
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] stargazer_5.2.2 jtools_2.0.1 lattice_0.20-38 MASS_7.3-51.1
## [5] forcats_0.4.0 stringr_1.4.0 dplyr_0.8.0.1 purrr_0.3.0
## [9] readr_1.3.1 tidyr_0.8.2 tibble_2.0.1 ggplot2_3.1.0
## [13] tidyverse_1.2.1 rmdformats_0.3.5 knitr_1.22
##
## loaded via a namespace (and not attached):
## [1] Rcpp_1.0.0 lubridate_1.7.4 assertthat_0.2.0 digest_0.6.18
## [5] mime_0.6 R6_2.4.0 cellranger_1.1.0 plyr_1.8.4
## [9] backports_1.1.3 evaluate_0.13 ggstance_0.3.1 httr_1.4.0
## [13] highr_0.7 pillar_1.3.1 rlang_0.3.1 lazyeval_0.2.1
## [17] readxl_1.3.0 rstudioapi_0.9.0 miniUI_0.1.1.1 rmarkdown_1.12
## [21] labeling_0.3 questionr_0.7.0 pander_0.6.3 munsell_0.5.0
## [25] shiny_1.2.0 broom_0.5.1 compiler_3.5.2 httpuv_1.4.5.1
## [29] modelr_0.1.4 xfun_0.5 pkgconfig_2.0.2 htmltools_0.3.6
## [33] tidyselect_0.2.5 bookdown_0.9 crayon_1.3.4 withr_2.1.2
## [37] later_0.8.0 grid_3.5.2 nlme_3.1-137 jsonlite_1.6
## [41] xtable_1.8-3 gtable_0.2.0 magrittr_1.5 scales_1.0.0
## [45] cli_1.0.1 stringi_1.3.1 promises_1.0.1 xml2_1.2.0
## [49] generics_0.0.2 tools_3.5.2 glue_1.3.0 hms_0.4.2
## [53] yaml_2.2.0 colorspace_1.4-0 rvest_0.3.2 haven_2.1.0