Pythonで重回帰分析を行い3次元での可視化をしてみる

数学的理論と計算

単回帰分析は、一つの従属変数を一つの独立変数で表すものでしたが、一つの独立変数を複数の独立変数で表す重回帰分析(Multiple Regression Analysis)も見てみましょう。

ここで行う重回帰分析の設定は、子供の身長(従属変数) y を母親の身長(独立変数)x と父親の身長(独立変数)z で推定してみます。

重回帰分析で分析で使うサンプルは、単回帰分析と同じように演習で身につける統計学入門のデータをダウンロードして使っています。

また、Pythonを使った重回帰分析の実装は以下のサイトを参考にしています。

Pythonで基礎から機械学習 「重回帰分析」 - Qiita
はじめに この「Pythonで基礎から機械学習」シリーズの目的や、環境構築方法、シリーズの他の記事などは以下まとめページを最初にご覧下さい。…

では実際にやってみましょう。

Sponsored Link

重回帰分析のための前処理

まず必要な以下のライブラリを読み込みます。

  • Pandas: DataFrameの取り扱う。
  • Numpy: 数値計算モジュール
  • Matplotlib: 描画ライブラリ

次に、エクセルフォーマットのデータセットを読み込み、DataFrameとして表示します。

# 必要なライブラリのインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

  # データセットの読み込み
mregl = pd.read_excel('Ex7-4 Regression-1.xlsx')
mregl = mregl.dropna(how = 'all', axis=1) # 欠損値の削除
mregl

上のコードを実行して作成したのが下記のDataFrame。

次に、x に説明変数全体を代入、x1に説明変数として母親の身長、x2に説明変数として父親の身長、yの目的変数として子供の身長を代入します。

x = mregl[['x', 'z']] 
y = mregl[['y']] 
x1 = mregl[['x']]
x2 = mregl[['z']]

# 配列の確認
print(x.shape)
print(y.shape)

shapeを使ってx と y の配列を確認します。

(6, 2)
(6, 1)

xの場合6x2、yの場合6x1の行列が生成されました。

複数の要素をグラフで可視化

x1 、x2、 y を3次元グラフで可視化するために必要なライブラリmatplotlibはすでにインポートしています。

さらに、3次元で可視化をするために必要なAxes3Dメソッドをインポートし3次元のグラフを描画してみましょう。

# 3次元描画メソッドのインポート
from mpl_toolkits.mplot3d import Axes3D

# グラフの設定
fig = plt.figure(figsize=(8,8)) 
ax = fig.add_subplot(111, projection='3d')

# 散布図の描画設定
ax.scatter3D (x1, x2, y)
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_zlabel('y')

plt.show()

サンプル数が少ないので寂しいグラフになりますが、一応三次元グラフになっています。

データのスケーリング

重回帰分析で考えなくてはならないのが、データのスケーリングです。

分析するデータによっては、入力単位や対象が全く違う場合があるので、それらを一つの規格にそろえる必要があるのです。

例えば長さ(cm, m) と重さ (kg, g) などを一様に比べても正確な結果が出なさそうなのは直感的に分かりますよね。

なので、単位をそろえる必要があるのです。

単位のそろえ方、つまりデータのスケーリングには、正規化と標準化の二つの方法があります。

正規化とは特徴量を0~1に変換するスケーリングのことを指し、標準化とは特徴量を平均が0、分散が1になるよう変換するスケーリングです。

スケーリングに関しては、Codexaさんの記事が詳しいので参照してください。

正規化・標準化を徹底解説 (Python 前処理 サンプルコード付き)
機械学習の前処理の1つである「正規化」と「標準化」を徹底解説しました。複数のPythonライブラリで正規化と標準化の実装をして見ましょう。(全Pythonコード収録)

問題は「今回のデータにスケーリングが必要なのか」ですが、ぶっちゃけ単位が同じなので、スケーリングは必要ないといっていいと思います。

しかし、練習もかねてスケーリングを行ってみてもいいと思うので、また別の記事にまとめたいと思います。

scikit-learnによる重回帰分析

では実際に重回帰分析を行ってみましょう。

scikit-learnを使った重回帰分析も基本的には単回帰分析と全く同じ手順で行います。

# 回帰分析に必要なライブラリのインポート
from sklearn.linear_model import LinearRegression
import numpy as np

# 回帰分析を実行
model_lr = LinearRegression()
model_lr.fit(x, y)
model_lr.coef_ # 係数 
a1, a2 = model_lr.coef_[0] # 係数を代入 
b = model_lr.intercept_ # 切片

では、可視化してみましょう。

# 三次元グラフの設定
fig = plt.figure(figsize=(8,8)) 
ax = fig.add_subplot(111, projection='3d')

# 散布図とラベルの設定
ax.scatter3D(x1, x2, y)
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_zlabel("y")

# 回帰平面の描画
mesh_x1 = np.arange(x1.min()[0], x1.max()[0], (x1.max()[0]-x1.min()[0])/30)
mesh_x2 = np.arange(x2.min()[0], x2.max()[0], (x2.max()[0]-x2.min()[0])/30)
mesh_x1, mesh_x2 = np.meshgrid(mesh_x1, mesh_x2)
mesh_y = a1*mesh_x1 + a2*mesh_x2 + b
ax.plot_wireframe(mesh_x1, mesh_x2, mesh_y)
plt.show()

print('モデル関数の回帰変数 w1: %.3f' %a1) 
print('モデル関数の回帰変数 w2: %.3f' %a2) 
print('モデル関数の切片 w2: %.3f' %b) 
print('y= %.3fx + %.3fz + %.3f' % (a1, a2 , model_lr.intercept_)) 
print('決定係数 R^2: %.3f'%model_lr.score(x, y))

上記のプログラムを実行して得られたのが、下記の3次元プロットです。

重回帰分析の説明

単回帰分析とは、目的変数(従属変数)yについて、説明変数(独立変数)xを使った式で表します。

そして重回帰分析の場合説明変数が二つ以上の場合を表します。

つまり、

そして総和の記号を使って表記すると、

となります。

今回の分析の場合回帰平面「生徒の身長(y) = 母親の身長(x) x 回帰係数 + 父親の身長(z)+ 切片(b)」グラフ上の青の平面を求めることで両親の身長から子供の身長を予測することができます。

回帰平面が示す値

重回帰分析で得られた式が表す事象を見てみましょう。

今回のモデル構築であられた回帰平面式は以下になります。

つまり母親の身長に回帰係数0.902 を掛け、それに父親の身長に回帰係数0.207を掛けたものを足し、50.455を引くと子供の身長が得られるといえます。

では両親の身長が、母147cm 、父163cmの場合、

(147 x 0.902) + (163 x 0.207) – 50.455 = 115.88

つまり子供の身長は約116cmくらいといえるでしょう。

実際に観測された値は117cmなので、大きく外れてはいないですね。

そして決定係数が0.971ですので、両親の身長が子供の身長に9割以上かかわっているといえるでしょう。

Sponsored Link

コメント

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