4  第6章 回帰分析

6章は変数間の関係を考察する手法の1つである回帰分析 (Regression Analysis) について説明します。

いま手元に売上高(yとする)と従業員数(xとする)という2つのデータの組 (y_i, x_i) があるとします。 i は企業の番号を表しており,n 社のデータがあるとします。 こんな感じのデータです。

企業番号 売上高 従業員数
1 1000 5
2 2000 10
3 3000 15
n 4500 25

n はサンプルサイズといいます。サンプル数という言い方は誤りです。サンプル数は1です。

いま、従業員数xが増えると売上高yは増えるのか否か、という分析をしたいとしましょう。 つまり、従業員数と売上高との間には関係があるのかどうかを調べたい、ということです。 しかし、関係があるといってもいろんな関係がある可能性があります。 そこで、変数間の関係で最も基本的なものとして線形関係 (linear relation) を考えます。

中学校の数学で学ぶy = ax + bです。

yx と線形関係であると考え分析のモデルを構築します。 これを「単回帰モデル」と呼び、次のように表します。

y_i = \beta_0 + \beta_1 x_i + u_i

ここで各変数は以下のように定義されます。

手元にある売上高yと従業員数xのデータを使って、横軸を従業員数、縦軸を売上高とした散布図に描くと次のようになります。

Code
従業員数と売上高の散布図
pacman::p_load(tidyverse, ggthemes, GGally, gt, gtExtra, knitr, kableExtra)

set.seed(123) # 乱数のタネ
n <- 15 # サンプルサイズ
x <- seq(1, 10, length.out = n) # 独立変数
y <- 3 + 1.5 * x + rnorm(n, mean = 0, sd = 2) # 従属変数
data <- data.frame(x = x, y = y) # データフレームの作成
my_font <- if (Sys.info()["sysname"] == "Darwin") "HiraKakuProN-W3" else "sans"

# 作図
g <- ggplot(data, aes(x = x, y = y)) +
    geom_point(size = 2.5, color = "black", alpha = 0.8) +
    theme_economist_white(base_family = my_font) +
        labs(
        title = "データの散布図",
        x = "従業員数 (x)",
        y = "売上高 (y)"
    )

print(g)

散布図をみると右肩上がりの関係があるように見えますが、もっと明確に変数間の関係を表すために、そのデータを最も良く説明できる直線をひこうと思います。 つまり、切片の\beta_0と傾きの\beta_1を決めるということです。 この直線が「モデル」で、それぞれの黒い点とモデルの直線との縦軸方向への距離を「誤差」または「残差」と呼びます。

Code
回帰式と誤差
model <- lm(y ~ x, data = data)
# 予測値をpredictedに格納
data$predicted <- predict(model)
# OSに合わせてフォントを自動選択(Macならヒラギノ、それ以外ならデフォルト)

g <- ggplot(data, aes(x = x, y = y)) +
    geom_segment(
        aes(xend = x, yend = predicted),
        color = "#D55E00", linetype = "dashed", alpha = 0.8, linewidth = 0.8
    ) +
    geom_point(size = 2.5, color = "black", alpha = 0.8) +
    theme_economist_white(base_family = my_font) +
    labs(
        title = "回帰式と誤差",
        x = "従業員数 (x)",
        y = "売上高 (y)"
    ) +
    geom_smooth(method = "lm", se = FALSE, color = "#0072B2", linewidth = 1.2) +
    theme(
        plot.title = element_text(face = "bold", size = 16),
        axis.title = element_text(size = 12),
    ) +
    annotate("text",
        x = min(data$x) + 2,
        y = max(data$y) + 1,
        label = "y[i] == beta[0] + beta[1] * x[i] + u[i]",
        parse = TRUE,
        size = 6, family = my_font
    )
print(g)

望ましい性質を備えた直線の引き方の1つとして、ガウス(Gauss)が構築した最小二乗法(Ordinaly Least Square Methods: OLS)について説明します。

4.1 分析準備

サンプルデータを読み込みます。 MS Excelのファイル .xlsx なので、readxl::read_xlsx() 関数を使います。 読み込んだデータから、2019年のデータを抽出します。

code 6-1 Excelデータの読み込み
firmdata <- readxl::read_xlsx("data/MktRes_firmdata.xlsx")
firmdata19 <- firmdata |>
    dplyr::filter(fyear == 2019) # 2019年を抽出

探索的なデータ分析として、変数間の関係を概観するために GGally パッケージの ggpairs() 関数を使います。

code 6-4 変数間の関係の概略
firmdata19 |>
    select(sales, mkexp, emp, operating_profit) |>
    GGally::ggpairs() +
    labs(title = "2変数の関係の概略")

出力された図を見てみます。

  • 対角線 (分布): 売上高 sales や従業員数 emp、営業利益 operating_profit は値の小さい左側にデータが集まっており、右側に裾を引く歪んだ分布であることがわかります。
  • 右上 (相関係数): Corr: として相関係数が表示されています。売上高 sales と従業員数 emp や営業利益 operating_profit の相関が高く、また営業利益と従業員数にも強い正の相関があります。
  • 左下 (散布図): 2変数間の散布図が表示されています。異常値の有無などを確認できます。

こういった図でデータを概観し、線形回帰モデルが適切かどうかを判断したり、異常値の有無を確認して分析結果の解釈に役立てたりします。

次に、図ではなく数値としてデータの特徴をつかむため記述統計量を計算します。 ここでは基本関数 summary() を使って計算します。

ds1 <- firmdata19 |>
    select(sales, mkexp, emp, operating_profit) |> # 変数を選択
    summary() # 記述統計量

knitr::kable(ds1, align = "cccc") |>
    kableExtra::kable_styling(latex_options = "hold_position")
sales mkexp emp operating_profit
Min. : 11333 Min. :0.01137 Min. : 163 Min. :-40469
1st Qu.: 183525 1st Qu.:0.16714 1st Qu.: 3454 1st Qu.: 7743
Median : 464450 Median :0.25448 Median : 7826 Median : 23904
Mean :1199403 Mean :0.29868 Mean : 20249 Mean : 81088
3rd Qu.:1164243 3rd Qu.:0.37506 3rd Qu.: 24464 3rd Qu.: 63068
Max. :9878866 Max. :0.75650 Max. :160227 Max. :656163

4.2 単回帰モデルと予測値

膨大なデータを目の前にした我々は、そのデータを最も良く「説明」できるシンプルなモデルを特定したいと考えます。 最も基本的な関数 f:x \rightarrow y として1次関数を考えます。

y = \beta_0 + \beta_1 x

ここで、\beta_0 は切片、\beta_1 は傾きを表します。 何らかの方法で\beta_0\beta_1を決めたとしよう。 その切片を \hat{\beta}_0、傾きを \hat{\beta}_1 とします。 x に手元にあるデータ x_i を代入して計算できる値を予測値 (predicted value) といい、\hat{y}_i と表します。

\hat{y}_i = \hat{\beta}_0 + \hat{\beta}_1 x_i

このとき、実際の観測値 y_i と予測値 \hat{y}_i の差を残差 (residual) といい、e_i で表します。

e_i = y_i - \hat{y}_i

回帰分析で最も良く用いられており、望ましい性質をもつ推定値を計算できる方法は最小二乗法といい、この残差e_iの二乗和 \sum e_i^2 を最小にするように \hat{\beta}_0\hat{\beta}_1 を決定します。

Rでは lm() 関数を使って計算できます。 ここでは、売上高が従業員数で説明できるかを調べる単回帰モデルを構築します。 sales_i = \beta_0 + \beta_1 emp_i + u_i

Rだと従属変数 ~ 独立変数という形で回帰式を指定します。

# 回帰モデルを構築
ols_model <- "sales ~ emp" # 回帰式の定義

モデルを最小自乗法で推定するには、lm()関数を使います。 lm()関数の第1引数に回帰式を、第2引数にデータフレームを指定します。 推定結果をreg1というオブジェクトに格納し、回帰係数を表示するにはcoef()関数を使います。

reg1 <- lm(formula = ols_model, data = firmdata19)
coef(reg1) # 回帰係数
(Intercept)         emp 
22113.98050    58.14081 

最小二乗法で推定された係数は以下のようになります。

\hat{sales}_i = 22113.98050 + 58.14081 \times emp_i

従業員が10名のときの売上高の予測値は22695.3886となり、従業員が1名増えるごとに売上高が約58.14増加すると予測されます。

4.3 回帰分析における推定と検定

4.3.1 回帰分析と統計的推測

この節は回帰分析の理屈を学習する上で重要な章なので、時間を掛けて学習することをオススメします。

4.3.2 企業データを用いた回帰分析の実行

上で推定した回帰分析の結果をみていきます。 lm()関数で推定した結果をreg1というオブジェクトに格納しているので、その中身をみてみましょう。 詳細を表示するにはsummary()関数を使います。

summary()関数は引数に指定するオブジェクトの型により異なる結果を返します。 ここでは、lmオブジェクトを引数に指定しているので、回帰分析の結果が表示されます。

summary(reg1)

Call:
lm(formula = ols_model, data = firmdata19)

Residuals:
     Min       1Q   Median       3Q      Max 
-1834902  -280228   -34549   136598  3292521 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 22113.980  89224.761   0.248    0.805    
emp            58.141      2.569  22.628   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 875800 on 144 degrees of freedom
Multiple R-squared:  0.7805,    Adjusted R-squared:  0.779 
F-statistic:   512 on 1 and 144 DF,  p-value: < 2.2e-16
confint(reg1, level = 0.99)
                    0.5 %       99.5 %
(Intercept) -210798.52845 255026.48944
emp              51.43362     64.84799

4.3.3 回帰係数の解釈

この節は難しいので、教科書の解説に補足を加えながら説明します。 例として次のような重回帰モデルを考えます。

y_i = \beta_0 + \beta_1 x_{1i} + \beta_2 x_{2i} + u_i

ここでx_{1i}の微少な変化がy_iに与える影響を知りたいとします。 この回帰モデルをx_{1i}で偏微分すると、次のようになります。

\frac{\partial y_i}{\partial x_{1i}} = \beta_1

つまりx_{2i}を一定としてx_{1i}が1単位変化した場合のy_iの変化量は\beta_1である、ということです。このことを他の変数を一定とした場合の効果 (ceteris paribus effect) といい、様々な要因で決定されているであろう従属変数に対して、特定の独立変数が与える影響を測定する際に重要な考え方となります。

4.3.4 単回帰モデルと重回帰モデルの比較

営業利益operating_profitを従属変数、広告宣伝費advを独立変数とした単回帰モデルを推定します。 summary()関数で結果を表示するのが簡単ですが、見づらいので、ここではmodelsummaryパッケージを使ってきれいに表示します。

reg2 <- lm(operating_profit ~ adv, data = firmdata19)
modelsummary::modelsummary(
    reg2,
    stars = c(`***` = 0.01, `**` = 0.05, `*` = 0.1),
    gof_omit = "AIC|BIC|Log.Lik|RMSE|F"
    )
(1)
* p
(Intercept) 57079.103***
(10568.681)
adv 1.257***
(0.216)
Num.Obs. 146
R2 0.191
R2 Adj. 0.185

近年は回帰分析の結果を適切に解釈するためにp値だけではなく、信頼区間も確認することが推奨されています。 Rではconfint()関数を使って信頼区間を計算します。 このconfint()関数で計算される信頼区間はデフォルトで95%信頼区間となっています。

confint(reg2) |> round(4) |> knitr::kable()
2.5 % 97.5 %
(Intercept) 36189.3110 77968.8944
adv 0.8304 1.6837

次に、営業利益operating_profitを従属変数、広告宣伝費adv、温度temp、従業員数emp、労働費用labor_cost、総資産total_assets、研究開発費rdを独立変数とした重回帰モデルを推定します。 教科書とは異なりますが、先にモデルを定義してからlm()関数に渡す方法で推定します。

multi_model <- "operating_profit ~ adv + temp + emp + labor_cost + total_assets + rd"

この回帰モデルをlm()関数で推定し、結果をsummary()関数で表示します。

reg3 <- lm(formula = multi_model, data = firmdata19)
reg <- list(reg2, reg3)
modelsummary::modelsummary(
    reg,
    stars = c(`***` = 0.01, `**` = 0.05, `*` = 0.1),
    gof_omit = "AIC|BIC|Log.Lik|RMSE|F"
    )
(1) (2)
* p
(Intercept) 57079.103*** 22090.415***
(10568.681) (8113.534)
adv 1.257*** -1.431***
(0.216) (0.295)
temp -1.878***
(0.631)
emp -1.510**
(0.704)
labor_cost 0.881***
(0.169)
total_assets 0.035***
(0.006)
rd 1.385***
(0.527)
Num.Obs. 146 146
R2 0.191 0.648
R2 Adj. 0.185 0.633

confint()関数を使って信頼区間を計算します。

confint(reg3) |> round(4) |> knitr::kable()
2.5 % 97.5 %
(Intercept) 6048.5160 38132.3132
adv -2.0151 -0.8470
temp -3.1260 -0.6298
emp -2.9014 -0.1190
labor_cost 0.5464 1.2153
total_assets 0.0236 0.0467
rd 0.3433 2.4265
Back to top