Pythonのstatsmodelsで線形回帰の重回帰分析を行う方法

Pythonのstatsmodelsで線形回帰の重回帰分析を行う方法 プログラミング

Pythonで重回帰分析を行いたい場合、次の二つが候補になります。

  • scikit-learn
  • statsmodels

実際、それぞれを用いた記事が検索でも出てきます。
scikit-learnで重回帰分析を説明している記事。
statsmodelsで重回帰分析を説明している記事。

正直、混乱しませんか?
私は、混乱しました。

結論を言うと、scikit-learnでもstatsmodelsでも線形回帰の重回帰分析は可能です。
極端な話、両方使ってもいいのです。
ケースに応じて使い分けるでもいいでしょう。

そこで、本記事ではstatsmodelsの導入から利用まで解説していきます。
使う使わないに関係なく、知っておいて損はないと思います。

本記事の内容

  • Pythonのstatsmodelsで重回帰分析を行うための環境
  • Pythonのstatsmodelsで重回帰分析を行う
  • scikit-learnとstatsmodelsの分析結果を比べる
  • Pythonのstatsmodelsで重回帰分析を行う方法のまとめ

なお、scikit-learnの導入から利用に関しては以下の記事で解説しています。

それでは、まずはPythonのstatsmodelsで重回帰分析を行うための環境の説明からです。

Pythonのstatsmodelsで重回帰分析を行うための環境

  • Windows 10 Home (バージョン1909)※以下の説明は64bit前提
  • Python 3.7.3
  • NumPy 1.18.5
  • Pandas 0.24.2
  • Matplotlib 3.2.1
  • statsmodels 0.11.1
  • scikit-learn  0.20.3

Pythonの上記ライブラリは、すべてインストールしておいてください。
scikit-learnは、データの標準化で利用します。

インストールコマンドを載せておきます。
statsmodelsの前提となるライブラリなどは適宜インストールしてください。

pip install numpy
pip install matplotlib
pip install pandas
pip install statsmodels
pip install scikit-learn

Matplotlibのグラフで日本語が文字化けする場合は、以下の記事をご覧ください。
この記事を参考にすれば、文字化けが解消できます。

環境の説明は、以上です。

Pythonのstatsmodelsで重回帰分析を行う

重回帰分析の対象データは、次の記事で用いたデータを利用します。
以下の記事内で「city_info.csv」へのリンクがあります。
そこから、ダウンロードしてください。

上の記事と同じ内容の分析を行います。
「議員報酬が、次の項目により予測できるかどうか?」です。

次の項目とは、「city_info.csv」にある項目です。

  • 都道府県
  • 財政力指数
  • 歳入
  • 人口
  • 面積
  • 人口密度

この場合では、議員報酬が目的変数です。
そして、上記の項目が説明変数となります。

なお、「city_info.csv」は以下のページのデータをもとに作成しています。
https://senkyo-local.info/m_ranking/
https://senkyo-local.info/f_ranking/

では、実際にこのデータを用いて、statsmodelsで重回帰分析を行っていきましょう。

データを準備する

city_info.csvをダウンロードしていない方は、ダウンロードしてください。
city_info.csvの内容(最初の5行)は、以下。

都道府県は、「北海道」という文字のままでは重回帰分析ができません。
そのため、都道府県コードに変更しています。

モジュール読み込み

statsmodelsを用いて重回帰分析を行います。
そのために必要なモジュールをimportします。

import numpy as np
import pandas as pd
import statsmodels.api as sm
from sklearn.preprocessing import StandardScaler

データ読み込み

DataFrame (データフレーム)として、読み込みます。
scikit-learnで重回帰分析した際と同じです。

# csv読み込み
df = pd.read_csv('./data/city_info.csv')

データを標準化する

基本的に、データを標準化することは必須と考えましょう。
適切な分析を行うには、必須だということです。

# 標準化
scaler = StandardScaler()
scaler.fit(np.array(df))
df_std = scaler.transform(np.array(df))
df_std = pd.DataFrame(df_std,columns=df.columns)

データの標準化については、次の記事で詳しく説明しています。
興味のある方は、そちらをご覧ください。

目的変数と説明変数を用意する

データフレームから抽出しています。
ここもscikit-learnで重回帰分析した際と同じように抽出します。

# 目的変数(Y)
Y = np.array(df_std['annual_income'])

# 説明変数(X)
col_name = ['prefecture_id', 'population', 'area', 'population_density', 'fiscal_index', 'revenue']
# 全要素が1.0の列を説明変数の先頭に追加(おまじない)
X = sm.add_constant(df_std[col_name])
X = np.array(X)

重回帰分析を実行する

scikit-learnも同じですが、たったこれだけで重回帰分析が可能です。
同じく、ライブラリ・モジュールの作成者に感謝です。

# モデルの設定(OLS:最小二乗法を指定)
model = sm.OLS(Y, X)

# 回帰分析の実行
results = model.fit()

分析結果を確認する

scikit-learnとは異なり、statsmodelsは結果の要約を作成してくれます。
以下のコードで確認できます。

# 結果の詳細を表示
print(results.summary())

ここまでのコードをまとめています。

import numpy as np
import pandas as pd
import statsmodels.api as sm
from sklearn.preprocessing import StandardScaler

# csv読み込み
df = pd.read_csv('./data/city_info.csv')

# 標準化
scaler = StandardScaler()
scaler.fit(np.array(df))
df_std = scaler.transform(np.array(df))
df_std = pd.DataFrame(df_std,columns=df.columns)

# 目的変数(Y)
Y = np.array(df_std['annual_income'])

# 説明変数(X)
col_name = ['prefecture_id', 'population', 'area', 'population_density', 'fiscal_index', 'revenue']
# 全要素が1.0の列を説明変数の先頭に追加(おまじない)
X = sm.add_constant(df_std[col_name])
X = np.array(X)

# モデルの設定(OLS:最小二乗法を指定)
model = sm.OLS(Y, X)

# 回帰分析の実行
results = model.fit()

# 結果の詳細を表示
print(results.summary())

このコードの実行結果は、以下。

レポート形式で表示されます。
この部分では、scikit-learnよりstatsmodelsの方が優秀ですね。

                            OLS Regression Results                            
==============================================================================
Dep. Variable:                      y   R-squared:                       0.728
Model:                            OLS   Adj. R-squared:                  0.726
Method:                 Least Squares   F-statistic:                     359.7
Date:                Tue, 23 Jun 2020   Prob (F-statistic):          2.85e-224
Time:                        12:05:25   Log-Likelihood:                -626.47
No. Observations:                 815   AIC:                             1267.
Df Residuals:                     808   BIC:                             1300.
Df Model:                           6                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const      -1.735e-16      0.018  -9.45e-15      1.000      -0.036       0.036
x1             0.0777      0.019      4.039      0.000       0.040       0.115
x2             1.2535      0.101     12.373      0.000       1.055       1.452
x3             0.1405      0.022      6.292      0.000       0.097       0.184
x4             0.2791      0.023     12.365      0.000       0.235       0.323
x5             0.2963      0.023     13.106      0.000       0.252       0.341
x6            -0.7372      0.098     -7.538      0.000      -0.929      -0.545
==============================================================================
Omnibus:                      101.361   Durbin-Watson:                   1.043
Prob(Omnibus):                  0.000   Jarque-Bera (JB):              947.359
Skew:                          -0.001   Prob(JB):                    1.92e-206
Kurtosis:                       8.282   Cond. No.                         11.7
==============================================================================


Warnings:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.

とりあえず、statsmodelsで重回帰分析ができました。
コード量と書き方を比べると、scikit-learnとstatsmodelsでは遜色はありません。

おまじない「sm.add_constant」が、若干手間なだけですね。
でも、どちらかの優劣を語れるほどの材料ではありません。


では、次以降では分析結果を比べていきます。

scikit-learnとstatsmodelsの分析結果を比べる

重回帰分析の結果において、ポイントは以下。

  • 回帰係数
  • 決定係数

これらの値を比較していきます。

回帰係数

statsmodelsのサマリーレポートでは、col_nameではなくX1などで表示されています。
X1はindex=0、X2はindex=1というように置き換えています。


col_namescikit-learnstatsmodels
5revenue-0.4354990372-0.7372
0prefecture_id0.076877984680.0777
2area0.15421651420.1405
3population_density0.30371679890.2791
4fiscal_index0.32921359980.2963
1population0.96466406391.2535

目的変数(議員報酬)に与える影響度の順番は、一致しました。
また、それぞれの値はほぼ同じと言えるでしょう。
scikit-learnでの分析と同じように、statsmodelsでも同じ結論です。

population(人口)が、目的変数(議員報酬)に最も影響を与えています。
そして、revenue(歳入)は、もっとも影響を与えていません。
むしろ、revenueは説明変数から除外した方がよいかもしれません。

決定係数

決定係数は、その回帰分析の精度を表す指標でした。
一般的に言われている目安は以下。

目安その1

決定係数精度
0.9以上非常によい
0.7以上0.9未満よい
0.5以上0.7未満あまりよくない
0.5未満悪い

目安その2

決定係数精度
0.8以上良い
0.5以上0.8未満やや良い
0.5未満良くない

最低でも0.5以上は、必要ということがわかります。
0.7以上あれば、合格と言えそうですね。


scikit-learnstatsmodels
通常の (自由度未調整) 決定係数0.72704409490407480.728
自由度調整済み決定係数なし(※)0.726

(※)自分で計算して求めれば、算出可能。

通常の決定係数は、ほぼ同じになります。
statsmodelsにだけ、自由度調整済み決定係数が表示されるようです。
表示というか、学習した時点で算出されているという方が正確ですね。

分析の結果としては、決定係数がstatsmodelsでも0.7以上です。
よって、目安からすると「よい」結果になります。
つまり、議員報酬を「よい」精度で予測できると言えます。

自由度調整済み決定係数も0.7以上となります。
なお、自由度調整済み決定係数とは、辛めの評価をした決定係数のことです。

Pythonのstatsmodelsで重回帰分析を行う方法のまとめ

scikit-learnとstatsmodelsを比較してきました。
コーディングする側面と機能面をメインにした比較です。

コーディングの面では、それほど変わりありません。
scikit-learnとstatsmodelsのどちらも同じぐらいです。

機能面では、次の点で違いがでました。
他にもあると思いますが、今回明確になった違いは以下の二つです。

  • statsmodelsではレポート形式で結果が表示される
  • statsmodelsでは自由度調整済み決定係数が算出される

ただ、scikit-learnでもロジックを組んで 自由度調整済み決定係数 を算出することは可能です。
そういう関数を一つ用意すれば、この差は大きいモノではありません。

また、レポート形式も同じように関数を作成すれば終わりです。
そう考えれば、scikit-learnとstatsmodelsの間に致命的な差はありません。

ただ、複雑な分析をしたい場合は事情が異なるかもしれません。
最小二乗法は基本中の基本です。

statsmodelsにしか存在しない分析手法があるということもあり得ます。
逆に、scikit-learnにしか存在しない分析手法があることも想定されます。

よって、最終的に言えることは以下となります。
scikit-learnとstatsmodelsを使い分ける」です。

どちらも利用するのに、それほど学習コストが必要ではありません。
比較的簡単に利用できます。

もっと言えば、両方で分析すればいいのです。
そして、今回のように結果を比較します。
そうすれば、分析の検証にもなります。

タイトルとURLをコピーしました