35
Help us understand the problem. What are the problem?
Organization

機械学習の基礎の基礎を1から

はじめに

本稿では機械学習の基礎の基礎として線形回帰について、Pythonのサンプルコードを併せて学んでいきます。

scikit-learnのデータセットであるカリフォルニアの住宅価格データセットから目的変数である住宅価格を予測します。

用語の説明

説明変数

目的変数を説明する変数のことです。例えば、「部屋数」「築年数」「緯度経度」から「住宅価格」を求める場合、この「部屋数」「築年数」「緯度経度」が説明変数となります。

目的変数

説明変数から予測された変数のことです。例えば、「部屋数」「築年数」「緯度経度」から「住宅価格」を求める場合、この「住宅価格」が目的変数となります。

回帰

予測する値が数値など連続する値のときのことです。例えば、「住宅価格」などは連続する値を取ることができるので回帰となります。

分類

予測する値がYes,Noのようなデータが属するクラスである場合のことです。カリフォルニアの住宅価格データセットには入っていませんが、例えば仮に、「ユニットバスかセパレートか」といった項目があれば分類となります。

線形回帰

さて、いよいよ機械学習の最も基本的な手法の1つである線形回帰について見ていきます。線形回帰とは回帰分析の一種で、目的変数の予測値yを説明変数xを用いて

y = a_1x_1 + a_2x_2 + \cdots  + a_nx_n

の形で表すことによって予測する手法です。

まずは、データセットの確認です。

import pandas as pd
from sklearn.datasets import fetch_california_housing

# カリフォルニアの住宅価格データセットの読み込み
california = fetch_california_housing()
# データフレームを表示
df = pd.DataFrame(california.data, columns=california.feature_names)
df['Price'] = california.target
print(df)
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude Price
0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 -122.23 4.526
1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 -122.22 3.585
... ... ... ... ... ... ... ... ... ...
20638 1.8672 18.0 5.329513 1.171920 741.0 2.123209 39.43 -121.32 0.781
20639 2.3886 16.0 5.254717 1.162264 1387.0 2.616981 39.37 -121.24 0.771

データは上図のようなモノとなっています。それでは、回帰分析をやってみましょう。

まずは、このデータの分布を見てみましょう。

# データの分布を確認
axes = df.hist(bins=48, figsize=(14,10))

すると、次のようなヒストグラムとなりました。
Figure_1.png

住宅価格の5付近に異常な数のデータがあることが確認できます。住宅価格が丸められているとするとモデル作成に悪影響を及ぼしてしまいます。なので、まず、こういったデータを除去する必要があります。

# 価格の最大値未満のデータのみ取得
df = df[df['Price'] < df['Price'].max()]

次に、説明変数xと目的変数yにデータを分けます。

# 説明変数
x = df.drop(['Price'], axis=1)
# 目的変数
y = df['Price']

次に、訓練データとテストデータを分けます。
こちらはscikit-learnのtrain_test_splitを使って実装します。
また、後の処理で目的変数の標準化を施すために、目的変数を二次元配列に変換します。

from sklearn.model_selection import train_test_split
# random_state=42で訓練データとテストデータを作成
x_training, x_test, y_training, y_test = train_test_split(x, y, test_size=0.1, random_state=42)
# y_training, y_testを二次元配列に変換
y_training = y_training.values.reshape(-1,1)
y_test = y_test.values.reshape(-1,1)

次に、各データを標準化します。標準化とはデータの平均を0、分散を1にすることで範囲の異なるそれぞれの変数を同様に扱うことが可能になります。こちらは、scikit-learnのStandardScalerで実装します。

from sklearn.preprocessing import StandardScaler
# 標準化
scaler_x = StandardScaler()
x_training = scaler_x.fit_transform(x_training)
x_test = scaler_x.transform(x_test)

scaler_y = StandardScaler()
y_training = scaler_y.fit_transform(y_training)
y_test = scaler_y.transform(y_test)

さて、いよいよ学習です。
今回は、標準化を施しているため、fit_intercept=Falseを指定します。

from sklearn.linear_model import LinearRegression
# 線形回帰実行
model = LinearRegression(fit_intercept=False)
model.fit(x_training, y_training)

これで学習は完了です。

結果の確認ですが、横軸を予測値、縦軸を実測値とした散布図を書き、正の相関を確認できれば「予測精度が良い」と判断できそうです。

また、定量化するためにスコア RMSE を計算します。今回、標準化により分散1となっているため、RMSEの値は1より十分に小さいことが求められます。

それではRMSEを計算し、散布図を書いてみます。

import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error

#RMSEを計算
rmse = mean_squared_error(y_test,model.predict(x_test), squared=False)
# 結果確認
plt.figure(figsize=(5,5))
plt.xlim(-3, 4)
plt.ylim(-3, 4)
plt.plot(model.predict(x_test), y_test, 'o')
plt.title('RMSE: {:.3f}'.format(rmse))
plt.xlabel('Predict')
plt.ylabel('Actual')
plt.grid()
plt.show()

散布図とRMSEは次のようになりました。

Figure_3.png

一部、外れている箇所もありますが、おおむね正の相関となりRMSE=0.670であることを確認できました。
今回は行いませんが、より良い精度を出すためにはより良いアルゴリズムを用いたりより良いデータの前処理を施したりする必要があります。

以下、コードまとめです。

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# カリフォルニアの住宅価格データセットの読み込み
california = fetch_california_housing()
# データフレームを表示
df = pd.DataFrame(california.data, columns=california.feature_names)
df['Price'] = california.target
print(df)

# データの分布を確認
axes = df.hist(bins=48, figsize=(14,10))

# 価格の最大値未満のデータのみ取得
df = df[df['Price'] < df['Price'].max()]

# 説明変数
x = df.drop(['Price'], axis=1)
# 目的変数
y = df['Price']

# random_state=42で訓練セットを作成
x_training, x_test, y_training, y_test = train_test_split(x, y, test_size=0.1, random_state=42)
# y_training, y_testを二次元配列に変換
y_training = y_training.values.reshape(-1,1)
y_test = y_test.values.reshape(-1,1)

# 標準化
scaler_x = StandardScaler()
x_training = scaler_x.fit_transform(x_training)
x_test = scaler_x.transform(x_test)

scaler_y = StandardScaler()
y_training = scaler_y.fit_transform(y_training)
y_test = scaler_y.transform(y_test)

# 線形回帰実行
model = LinearRegression(fit_intercept=False)
model.fit(x_training,y_training)

#予測精度の確認
rmse = mean_squared_error(y_test,model.predict(x_test), squared=False)

# 結果確認
plt.figure(figsize=(5,5))
plt.xlim(-3, 4)
plt.ylim(-3, 4)
plt.plot(model.predict(x_test), y_test, 'o')
plt.title('RMSE: {:.3f}'.format(rmse))
plt.xlabel('Predict')
plt.ylabel('Actual')
plt.grid()
plt.show()
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
35
Help us understand the problem. What are the problem?