【機械学習入門】ボストンの住宅価格データセットを線形回帰モデルで分析してみよう

# 本記事の概要
scikit-learnのボストンの住宅価格データセットを活用し、**ボストンの住宅価格**を予測するモデルを作成します。
教師あり学習の機械学習手法で回帰に利用される**線形回帰モデル**を実践的に学びます。
「機械学習を触ってみたいけど、データもないからどこから手を付けていいか分からない。」
そんな方にも機械学習の入門としておすすめです。

# 目次
[1. データセットの確認](#1-データセットの確認)
[2. データの可視化](#2-データの可視化)
[3. モデルの作成(線形モデル)](#3-モデルの作成(線形モデル))
[4. モデルの検証](#4-モデルの検証)
[5. モデルの改良](#5-モデルの改良)
[6. 残差プロット](#6-残差プロット)
[7. おわりに](#7-おわりに)

#1. データセットの確認
まずはじめに、[ボストンの住宅価格データセット](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_boston.html)をscikit-learnのライブラリからダウンロードをしましょう。
ダウロード後にpandasを活用してデータの確認をします。

```python
import pandas as pd
from sklearn.datasets import load_boston

# ボストンデータセットの読み込み
boston = load_boston()
# ボストンデータセットのデータフレームの作成
df = pd.DataFrame(boston.data, columns=boston.feature_names)
# 目的変数(PRICE)をデータフレームに結合
df['PRICE'] = np.array(boston.target)
# ボストンデータセットの変数の説明の表示
print(boston['DESCR'])
```

データフレームの出力結果は以下の通りです。
レコード数は506個、変数は14個(うち1個は目的変数(PRICE))であることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1529393/8b10a46b-16fe-c57a-579c-5f84119b4f3d.png)
また、DESCRに各変数(目的変数以外)の概要が記述されているので、表示をさせてみます。
(※日本語要約は理解をしやすくするため追記しています)
>**Data Set Characteristics:**  
>
>    :Attribute Information (in order):
>        - CRIM     per capita crime rate by town ：犯罪発生率
>        - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.　：25000平方フィート以上の住宅区間の割合
>        - INDUS    proportion of non-retail business acres per town　：非小売業の土地面積の割合
>        - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)　：チャールズ側沿いかどうか(1:川沿い、0：川沿いではない)
>        - NOX      nitric oxides concentration (parts per 10 million)　：窒素酸化物の濃度
>        - RM       average number of rooms per dwelling　：一戸あたりの平均部屋数
>        - AGE      proportion of owner-occupied units built prior to 1940　：1940年よりも前に建てられた家屋の割合
>        - DIS      weighted distances to five Boston employment centres　：ボストンの主な雇用圏までの重み付き距離
>        - RAD      index of accessibility to radial highways　：幹線道路へのアクセス指数
>        - TAX      full-value property-tax rate per $10,000　：10000ドルあたりの所得税率
>        - PTRATIO  pupil-teacher ratio by town　：教師あたりの生徒の数
>        - B        1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town　：アフリカ系アメリカ人居住者の割合
>        - LSTAT    % lower status of the population　：低所得者の割合
>

#2. データの可視化
次に各変数間のペアプロットを表示し、データの相関を確認してみましょう。
データを可視化することで、あらかじめデータ間の相関が予測されたり、異常な点を見つけたりすることができます。

```python
# pandasのscatter_matrix関数を使いペアプロットを表示
from pandas.plotting import scatter_matrix
fig = pd.plotting.scatter_matrix(df, figsize=(15,15))
```

目的変数(PRICE, 一番下の行)と各説明変数に着目してみると、RM(一戸あたりの平均部屋数, 6列目)などは明らかな右肩上がりの関係を持つことが確認できます。
当たり前ですが、部屋数が増えると住宅価格が上がる、という関係があることが分かりますね。

その他にも、犯罪発生率(CRIME, 1列目)が低いと、低所得者の割合が低い(LSTAT, 13列目)と、住宅価格は高くなる関係があることも分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1529393/2e4ef549-bcd8-efe7-4b2c-80010b629588.png)

#3. モデルの作成(線形モデル)
それではいよいよモデルの作成に移っていきましょう。
今回は、線形モデルを作成し、住宅価格の予測をしてみます。
「2.データの可視化」で相関が見られた2変数(RM, CRIME)を活用してモデルを作成します。

```python
from sklearn.model_selection import train_test_split
# 説明変数の抽出(CRIME、RM)
data = df.loc[:,['CRIM','RM']].values
# 目的変数の抽出
target = df.loc[:,'PRICE'].values
# データの分割(訓練データ、検証データ)
X_train, X_test, y_train, y_test = train_test_split(data, target, random_state=0)

# sklearnモジュールからLinearRegressionをインポート
from sklearn.linear_model import LinearRegression
# 線形モデルのオブジェクト生成
model = LinearRegression()
# モデルの学習
model.fit(X_train, y_train)
```
これで線形モデルの学習が終わりました。

試しにモデルを活用して住宅価格を予測してみましょう。
例えば、犯罪発生率(CRIM)=0.2、部屋数(RM)=6とすると、下記の住宅価格の予測値が得られました。

```python
model.predict([[0.2, 6]])
> array([20.94426001])
```

一方で、犯罪発生率(CRIM)=10、部屋数(RM)=6のように犯罪発生率を大きくしてみると、住宅価格が約＄3,000安くなると予測されました。

```python
model.predict([[10, 6]])
> array([17.81097374])
```

#4. モデルの検証
続いて作成したモデルの性能を評価します。

```python
# 作成したモデルから予測(学習用、検証用モデル使用)
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)

# 誤差の計算
from sklearn.metrics import mean_squared_error
# 平均二乗誤差：小さいほど誤差の小さなモデルと言える
print('MSE Train : %.3f, Test : %.3f' % (mean_squared_error(y_train, y_train_pred), mean_squared_error(y_test, y_test_pred)))
# 決定係数：回帰式の適合性の指標(1に近いほど良い)
print('R^2 Train : %.3f, Test : %.3f' % (model.score(X_train, y_train), model.score(X_test, y_test)))
> MSE Train : 37.004, Test : 44.945
> R^2 Train : 0.566, Test : 0.450
```

今回作成した2変数の線形重回帰モデルは、誤差が大きく、決定係数≦0.5なので、適合度が低いことがわかります。
2変数だけだと正確な予測が出来ないということですね。

#5. モデルの改良
2変数だけだと予測精度が低いので、単純に説明変数を増やしてみましょう。

```python
# 説明変数の抽出(13個の変数)
data = df.loc[:,'CRIM':'LSTAT'].values
print(data2.shape)
> (506, 13)

# 以下は先ほどのデータ処理と同様の処理を実施
X_train, X_test, y_train, y_test = train_test_split(data, target, random_state=0)

model = LinearRegression()
model.fit(X_train, y_train)

y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)

print('MSE Train : %.3f, Test : %.3f' % (mean_squared_error(y_train, y_train_pred), mean_squared_error(y_test, y_test_pred)))
print('R^2 Train : %.3f, Test : %.3f' % (model.score(X_train, y_train), model.score(X_test, y_test)))
> MSE Train : 19.641, Test : 29.782
> R^2 Train : 0.770, Test : 0.635
```
先ほどの2変数のモデルと比較し、説明変数が増えたことにより誤差が小さくなり、決定係数≧0.5と適合度も向上させることができました。
ただし、精度としてはさらに向上させる余地がありそうですね。

#6. 残差プロット
モデルの改良、および検証まで終わったので、残差プロットを作成して外れ値を確認してみましょう。

```python
import matplotlib.pyplot as plt
plt.scatter(y_train_pred, y_train_pred - y_train, c = 'blue', marker = 'o', label = 'Train Data')
plt.scatter(y_test_pred, y_test_pred - y_test, c = 'green', marker = 's', label = 'Test Data')
plt.xlabel('Predicted Values')
plt.ylabel('Residuals')
plt.legend(loc='upper left')
plt.hlines(y = 0, xmin = -10, xmax = 50, lw = 2, color = 'red')
plt.xlim([10,50])
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1529393/f0b61c1f-4239-a0af-2627-14501ec8f085.png)

プロットから、どうやら右下の方に外れ値が存在していることが確認されます。
綺麗な直線であることからも、何かしらデータに問題がありそうですね。
記事には示しませんが、改良前の2変数で作成したモデルにも同様の外れ値が見られたので、CRIM、RMとPRICEの関係を確認します。

```python
import seaborn as sns
pg = sns.pairplot(df[['PRICE','RM']])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1529393/fcd20fd2-a151-1a49-8dbe-9133b2b99fff.png)

散布行列図を確認すると、どうやらPRICEの上限が50に設定されていることが分かります。
このようなデータの制限、偏りが原因で外れ値が出てしまったと考えられます。

#7. おわりに
今回は、ボストンの住宅価格データセットを用いて、住宅価格の線形回帰モデルを作成しました。
変数を増やすことで精度を上げることができましたが、更なる精度向上には、データの前処理の工夫やモデルの変更等が必要になると考えられます。

#機械学習入門のリンク
今後も引き続き機械学習の実装入門を記事にしていきます。
参考にどうぞ。

・線形回帰モデル　本記事
・[非線形回帰モデル](https://qiita.com/kwi0303/items/283eea5211f9ca4c2a05)
・[k-近傍法](https://qiita.com/kwi0303/items/98d5455db06e82bc7a6d)
・[ロジスティック回帰モデル](https://qiita.com/kwi0303/items/8c5d092bb89a5994fe61)
・[主成分分析](https://qiita.com/kwi0303/items/5bb59482a8ad73c0a976)
・[K-means](https://qiita.com/kwi0303/items/57157a2e773979545ee8)
・サポートベクターマシン　※今後更新予定