【高等学校情報科 情報Ⅱ】教員研修用教材：重回帰分析とモデルの決定（python）

# はじめに
今回は文部科学省のページで公開されている情報Ⅰの教員研修用教材の「第3章 情報とデータサイエンス　前半」内の「重回帰分析とモデルの決定」についてみていきたいと思います。
「重回帰分析とモデルの決定」の前章ではExcelとPythonを使用して、データの整形・前処理・操作・欠損値と異常値の取扱いなどについて扱っていますが、この章からは「重回帰分析とモデルの決定」を行っていきます。
しかしRでの実装例しか書いていないので、pythonでの実装について考えていきたいと思います。

# 教材
[高等学校情報科「情報Ⅱ」教員研修用教材（本編）：文部科学省](https://www.mext.go.jp/a_menu/shotou/zyouhou/detail/mext_00742.html "高等学校情報科「情報Ⅱ」教員研修用教材（本編）：文部科学省")
[第3章 情報とデータサイエンス 前半 (PDF:8.9MB) PDF](https://www.mext.go.jp/content/20200702-mxt_jogai01-000007843_004.pdf "第3章 情報とデータサイエンス 前半 (PDF:8.9MB) PDF")

#環境
- ipython
- [Colaboratory - Google Colab](https://colab.research.google.com/notebooks/welcome.ipynb "Colaboratory - Google Colab")

#概要
教材の重回帰分析とモデルの決定内のp131から説明されている「（2）統計ソフト R での重回帰分析の実行」

> 重回帰分析のコンピュータでの実行と出力

の箇所でRで書かれてる実装例をpythonに書き換えていきたいと思います

# 前提
今回、前章までで分析を行う対象のデータはすでに整形を行った以下のファイルを使用しました。
[high_male_data.csv](https://drive.google.com/file/d/1bWOtAxvsGCEYW5Imy8fVjX5MFoF4zq8d/view?usp=sharing)

# 重回帰分析とモデルの決定

## 重回帰分析の実行

### pythonのソースコード

> stasmodelには、様々な線形回帰モデルがあります。 基本的なもの（最小二乗法、OLS）からより複雑なもの（反復再重み付け最小二乗法、IRLS）まであります． stasmodelの線形モデルには、2つの主なインターフェースがあります。
配列ベースのものと、formula式ベースのものです。
(第2版　Pythonによるデータ分析入門　NumPy,pandasを使ったデータ処理　より)

教材のコードは、最小二乗法(OLS)を使用しているので、ここでもOLSを使います。
まずは、教材のソースコードに近いformula式ベースのコードと配列ベースのコード両方見ていきたいと思います。

#### formula式

```python

import pandas as pd
import statsmodels.formula.api as smf
high_male = pd.read_csv('/content/high_male_data.csv')

model = smf.ols('X50m走 ~ 立ち幅跳び + ハンドボール投げ + 握力得点 + 上体起こし得点', data = high_male)
results = model.fit()
print(results.summary())
```

#### 配列ベース

```python
import pandas as pd
import statsmodels.api as sm

high_male = pd.read_csv('/content/high_male_data.csv')
x = high_male[['立ち幅跳び', 'ハンドボール投げ', '握力得点','上体起こし得点']]
y = high_male['X50m走']
x = sm.add_constant(x)
model = sm.OLS(high_male['X50m走'], x)
results = model.fit()
print(results.summary())
```

### pythonによる出力結果

#### formula式

```console
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  X50m走   R-squared:                       0.525
Model:                            OLS   Adj. R-squared:                  0.510
Method:                 Least Squares   F-statistic:                     36.18
Date:                Mon, 20 Jul 2020   Prob (F-statistic):           2.39e-20
Time:                        04:16:26   Log-Likelihood:                -41.639
No. Observations:                 136   AIC:                             93.28
Df Residuals:                     131   BIC:                             107.8
Df Model:                           4                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     10.8194      0.325     33.331      0.000      10.177      11.462
立ち幅跳び         -0.0120      0.002     -7.648      0.000      -0.015      -0.009
ハンドボール投げ      -0.0144      0.006     -2.367      0.019      -0.026      -0.002
握力得点          -0.0402      0.024     -1.677      0.096      -0.088       0.007
上体起こし得点       -0.0255      0.020     -1.264      0.208      -0.065       0.014
==============================================================================
Omnibus:                        3.064   Durbin-Watson:                   1.813
Prob(Omnibus):                  0.216   Jarque-Bera (JB):                2.955
Skew:                           0.359   Prob(JB):                        0.228
Kurtosis:                       2.927   Cond. No.                     2.61e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.61e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
```

#### 配列ベース

```console
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  X50m走   R-squared:                       0.525
Model:                            OLS   Adj. R-squared:                  0.510
Method:                 Least Squares   F-statistic:                     36.18
Date:                Mon, 20 Jul 2020   Prob (F-statistic):           2.39e-20
Time:                        04:15:11   Log-Likelihood:                -41.639
No. Observations:                 136   AIC:                             93.28
Df Residuals:                     131   BIC:                             107.8
Df Model:                           4                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         10.8194      0.325     33.331      0.000      10.177      11.462
立ち幅跳び         -0.0120      0.002     -7.648      0.000      -0.015      -0.009
ハンドボール投げ      -0.0144      0.006     -2.367      0.019      -0.026      -0.002
握力得点          -0.0402      0.024     -1.677      0.096      -0.088       0.007
上体起こし得点       -0.0255      0.020     -1.264      0.208      -0.065       0.014
==============================================================================
Omnibus:                        3.064   Durbin-Watson:                   1.813
Prob(Omnibus):                  0.216   Jarque-Bera (JB):                2.955
Skew:                           0.359   Prob(JB):                        0.228
Kurtosis:                       2.927   Cond. No.                     2.61e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.61e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
```

- coef:係数の推定値
- R-squared: 寄与率(決定係数)
- Adj. R-squared: 自由度修正済みR2

そのほか、LinearRegressionを使う方法などもあります。
今回、細かいパラメータについての説明は省きます。

### [参考]Rのソースコード(教材より)

```R
# データの読み込み
high_male <- read.csv("high_male_data.csv")
# 4 つの説明変数による重回帰分析
res <- lm(X50m走 ~ 立ち幅跳び + ハンドボール投げ + 握力得点 + 上体起こし得点, data = high_male)
summary(res)
```

lm()は引数パラメータweights = nullの場合、OLS使用(ordinary least squares is used.)

### [参考]Rによる出力結果

```console
Call:
lm(formula = X50m走 ~ 立ち幅跳び + ハンドボール投げ + 
    握力得点 + 上体起こし得点, data = high_male)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.66229 -0.22824 -0.03057  0.22797  0.99194 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)      10.819417   0.324609  33.331  < 2e-16 ***
立ち幅跳び       -0.012005   0.001570  -7.648 3.89e-12 ***
ハンドボール投げ -0.014393   0.006081  -2.367   0.0194 *  
握力得点         -0.040185   0.023969  -1.677   0.0960 .  
上体起こし得点   -0.025489   0.020163  -1.264   0.2084    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3349 on 131 degrees of freedom
Multiple R-squared:  0.5249,	Adjusted R-squared:  0.5104 
F-statistic: 36.18 on 4 and 131 DF,  p-value: < 2.2e-16

```

- Estimate:係数の推定値
- Residual standard error:（残差）標準誤差
- degrees of freedom（残差）自由度
- Multiple R-squared:寄与率　R2
- Adjusted R-squared:自由度修正済みR2

## モデル選択（モデリング）

### pythonのソースコード

pythonによるステップワイズ法によって、モデル選択を行っていきます。
私の調べ方が悪く、pythonモジュールなどでステップワイズ法が行えるようなものが見つからなかったので、今回はAIC(赤池の情報規準)の値が最も小さくなるようなモデルを選択できるように実装します。

```python

import pandas as pd
import statsmodels.formula.api as smf

high_male = pd.read_csv('/content/high_male_data.csv')
descriptors = ['立ち幅跳び', 'ハンドボール投げ', '握力得点','上体起こし得点']

model = smf.ols('X50m走 ~ ' + ' + '.join(descriptors), data = high_male)
results = model.fit()

print(results.summary())

best_aic = results.aic
best_model = model
dict_models = {}
while descriptors:
    desc_selected = ''
    flag = 0
    #dict_fitsに辞書keys:削除対象変数　values:[モデル値,AIC]
    for rm_desk in descriptors:
        used_desks = descriptors.copy()
        used_desks.remove(desk)
        formula = 'X50m走 ~ ' + ' + '.join(used_desks)
        resultmodel = smf.ols(formula = formula, data = high_male)
        dict_models[rm_desk] = [resultmodel, resultmodel.fit().aic]
    #AICが最小になる
    min_k, min_v = min(dict_models.items(), key=lambda x: x[1][1])
    if min_v[1] < best_aic:
        best_model = min_v[0]
        best_aic = min_v[1]
        descriptors.remove(min_k)
    else:
        #削減してもAICの改善が行われなかったら終了
        break

stepwise_model_fit = best_model.fit()
print(stepwise_model_fit.summary())
```

### pythonによる出力結果

```console

                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  X50m走   R-squared:                       0.525
Model:                            OLS   Adj. R-squared:                  0.510
Method:                 Least Squares   F-statistic:                     36.18
Date:                Sat, 25 Jul 2020   Prob (F-statistic):           2.39e-20
Time:                        02:25:36   Log-Likelihood:                -41.639
No. Observations:                 136   AIC:                             93.28
Df Residuals:                     131   BIC:                             107.8
Df Model:                           4                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     10.8194      0.325     33.331      0.000      10.177      11.462
立ち幅跳び         -0.0120      0.002     -7.648      0.000      -0.015      -0.009
ハンドボール投げ      -0.0144      0.006     -2.367      0.019      -0.026      -0.002
握力得点          -0.0402      0.024     -1.677      0.096      -0.088       0.007
上体起こし得点       -0.0255      0.020     -1.264      0.208      -0.065       0.014
==============================================================================
Omnibus:                        3.064   Durbin-Watson:                   1.813
Prob(Omnibus):                  0.216   Jarque-Bera (JB):                2.955
Skew:                           0.359   Prob(JB):                        0.228
Kurtosis:                       2.927   Cond. No.                     2.61e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.61e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
                            OLS Regression Results                            
==============================================================================
Dep. Variable:                  X50m走   R-squared:                       0.519
Model:                            OLS   Adj. R-squared:                  0.508
Method:                 Least Squares   F-statistic:                     47.50
Date:                Sat, 25 Jul 2020   Prob (F-statistic):           6.92e-21
Time:                        02:25:36   Log-Likelihood:                -42.463
No. Observations:                 136   AIC:                             92.93
Df Residuals:                     132   BIC:                             104.6
Df Model:                           3                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
Intercept     10.7121      0.314     34.114      0.000      10.091      11.333
立ち幅跳び         -0.0121      0.002     -7.703      0.000      -0.015      -0.009
ハンドボール投げ      -0.0169      0.006     -2.929      0.004      -0.028      -0.005
握力得点          -0.0439      0.024     -1.841      0.068      -0.091       0.003
==============================================================================
Omnibus:                        2.668   Durbin-Watson:                   1.820
Prob(Omnibus):                  0.263   Jarque-Bera (JB):                2.632
Skew:                           0.334   Prob(JB):                        0.268
Kurtosis:                       2.867   Cond. No.                     2.51e+03
==============================================================================

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.51e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
```

### コメント

立ち幅跳び , ハンドボール投げ , 握力得点 , 上体起こし得点はステップワイズ法によって、立ち幅跳び , ハンドボール投げ , 握力得点を使ったモデルが選択されたようです。おそらく、AIC(赤池の情報規準)もこの組合せのときが、一番小さくなると考えられます。
AICの値がRの値とpythonの値で異なっているのは、気になりますがpythonのものでも正しく機能しているように見えます。
pythonで実装したステップワイズ法でも、Rのものと同じものを選択できているようでした。
今後は、ほかのモデル選択法等も検討してみるといいかもしれません。

### [参考]Rのソースコード(教材より)

ステップワイズ法（変数増減法）を使って、適切なモデルを選択していています。

```R
# データの読み込み
high_male <- read.csv("high_male_data.csv")
# 全ての説明変数によるステップワイズ法（変数増減法）による重回帰分析
res <- lm(X50m走 ~ 立ち幅跳び + ハンドボール投げ + 握力得点 + 上体起こし得点, data = high_male)
step(res)
```
### [参考]Rによる出力結果

```console
Start:  AIC=-292.67
X50m走 ~ 立ち幅跳び + ハンドボール投げ + 握力得点 + 
    上体起こし得点

                   Df Sum of Sq    RSS     AIC
- 上体起こし得点    1    0.1792 14.868 -293.02
<none>                          14.689 -292.67
- 握力得点          1    0.3152 15.004 -291.79
- ハンドボール投げ  1    0.6281 15.317 -288.98
- 立ち幅跳び        1    6.5586 21.248 -244.47

Step:  AIC=-293.02
X50m走 ~ 立ち幅跳び + ハンドボール投げ + 握力得点

                   Df Sum of Sq    RSS     AIC
<none>                          14.868 -293.02
- 握力得点          1    0.3817 15.250 -291.58
- ハンドボール投げ  1    0.9663 15.835 -286.46
- 立ち幅跳び        1    6.6831 21.552 -244.54

Call:
lm(formula = X50m走 ~ 立ち幅跳び + ハンドボール投げ + 
    握力得点, data = high_male)

Coefficients:
     (Intercept)        立ち幅跳び  ハンドボール投げ          握力得点  
        10.71205          -0.01210          -0.01689          -0.04389  
```


# ソースコード
python版
https://gist.github.com/ereyester/5c6e5a9b8aa55ba826c7c96a4daf7814

R版
https://gist.github.com/ereyester/b42e8d36bf47f70e7092a0d0bd44e673