以前の記事でscikit-learnを使った「分類」の例を紹介したが、今回は別のデータセットを使って「回帰分析」をやっていく。

回帰は主に物事の予測に用いられる分析手法で「単回帰分析」と「重回帰分析」に分けられる。

一つの変数(説明変数)から、一つの値(目的変数)を予測するものを「単回帰分析」、複数の説明変数から目的変数を予測するものを「重回帰分析」と言う。

今回はscikit-learnを使った「重回帰分析」の簡単な例を紹介する。

データセットの読み込み

今回もscikit-learnで用意されているデータセットを使用する。

※米国ボストン市郊外、地域別の住宅価格。

from sklearn.datasets import load_boston
import pandas as pd

boston = load_boston()

# データフレームに変換して内容を確認
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df['目的変数(住宅価格)'] = boston.target
df.head()

説明変数の内容は下記表のとおり。

CRIM犯罪発生率
ZN住居区画の密集度
INDUS非小売業の土地割合
CHASチャールズ川 (1: 川の周辺, 0: それ以外)
NOXNOx濃度
RM平均部屋数
AGE1940年より前に建てられた物件割合
DIS5つのボストン市の雇用施設からの重み付き距離
RAD大きな道路へのアクセスしやすさ
TAX$10,000ドルあたりの所得税率
PTRATIO教師あたりの生徒数
B黒人の比率 1000(Bk – 0.63)^2
LSTAT低所得者の割合

データの前処理

次に取得したデータセットを説明変数(x)、目的変数(y)に分ける。

y = boston.target
x = boston.data

さらにxとyをそれぞれ訓練用データ、テスト用データに分ける。

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, shuffle=True)

今回はテストデータの割合を20パーセントにしてみた。

モデルに訓練用データを与え学習させる

前処理で用意した訓練用データ(x_train, y_train)を与え、モデルに学習させる。

from sklearn import linear_model

model = linear_model.LinearRegression()
model.fit(x_train, y_train)

学習したモデルの切片と係数を確認してみよう。

# 切片
print(model.intercept_)

# 偏回帰係数(重み)
desc = [
    '犯罪発生率', '住居区画の密集度', '非小売業の土地割合',
    'チャールズ川 (1: 川の周辺, 0: それ以外)', 'NOx濃度',
    '平均部屋数', '1940年より前に建てられた物件割合',
    '5つのボストン市の雇用施設からの重み付き距離',
    '大きな道路へのアクセスしやすさ', '$10,000ドルあたりの所得税率',
    '教師あたりの生徒数', '黒人の比率', '低所得者の割合'
]
df_tmp = pd.DataFrame(model.coef_, index=boston.feature_names, columns=['重み'])
df_tmp['説明'] = desc
df_tmp

係数(重み)を見てみると「CHAS(川の周辺かどうか)」、「平均部屋数」、「大きな道路へのアクセス」の値が高く、住宅価格に大きな影響を与えることが分かる。

テストデータを使ってモデルの精度を評価する

モデルの精度の指標として、決定係数という値がある。

これは1に近いほど分析の精度が高いことを意味する。

score関数にテストデータを渡し、決定係数を確認してみよう。

print(model.score(x_test, y_test))

# 0.7198637341775773

重回帰分析の場合、0.5が精度の目安と言われているので、今回の結果はまずまずと言えるだろう。

実際に10個のテストデータと予測結果を比較したものを見てみよう。

for i in range(10):
    print('テストデータ:' + str(y_test[i]))
    print('予測結果:' + str(model.predict([x_test[i]])) + '\n')

多少のバラつきはあるが、大きく外すことなく目的変数を求めることができている。