覚え書きブログ

scikit-learnを用いた機械学習(教師あり学習 1/3)

Pythonの代表的な機械学習ライブラリであるscikit-learnを用いて教師あり学習の回帰と分類を実装し、実際にデータから関数を学習していきます。

Scikit-learnとは

scikit-learnは、オープンソース機械学習ライブラリで、機械学習の基本的な教師あり学習手法(分類、回帰、モデル選択など)、および教師無し学習手法(クラスタリング、次元削減など)とともに、機械学習に必要とされる汎用的なデータ前処理や評価の機能を提供します。PythonのNumpyなどと連携するように設計されており、使いやすさと実用性とを兼ね備えているため、非常に人気のライブラリです。
f:id:hirotaka_hachiya:20190527222626p:plain

教師あり学習のフロー

教師あり学習のプログラムを一般的なフローは以下のようになります。
f:id:hirotaka_hachiya:20190528002430p:plain

以下、物件価格データの敷地面積LotAreaを入力とし、販売価格SalePriceの回帰を例にフローを説明していきます。
一つ一つjupyter notebookでコードを入力し、実行結果をみながら確認していきましょう。
f:id:hirotaka_hachiya:20190528130916p:plain

教師ありデータの準備

まず、入力 xと出力 yの対のデータを準備します。

以下のようにデータをpandas.DataFrameに読み込みXとyに代入します。

import pandas as pd
data = pd.read_csv('house_prices_train.csv')  # DataFrameの読み込み
data = data[data['MSSubClass'] == 20]  # 建物の等級MSSubClassを20(1階建て、1946年以降)に限定
X=data[['LotArea']].values  # 入力データ
y=data['SalePrice'].values  # 出力データ

データの前処理

入力データが複数ある場合、 データの値の大きさ(スケール)を揃える必要があります。一般的には、標準化と呼ばれる以下のような式で、データの平均が0で、標準偏差が1になるようにデータのスケールを揃えます。
f:id:hirotaka_hachiya:20190528001245p:plain

以下のように、numpyを用いると簡単に標準化できます。

Xmean = np.mean(X,axis=0)  # 平均
Xstd = np.std(X,axis=0)  # 標準偏差
Xnorm=(X - Xmean)/Xstd  # 標準化

print(np.mean(Xnorm))
print(np.std(Xnorm)
5.96537744574711e-17  # 標準化後の平均(ほぼ0)
0.9999999999999999  #標準化後の標準偏差(ほぼ1)

訓練用と評価用とに教師データを分割

ランダムまたは何らかの運用上のルール(例えば、期間)に従い、教師データ \{X, y\}を、訓練用 \{Xtr, ytr\}と評価用 \{Xte, yte\}とに分けます。

データの分割には、scikit-learnのtrain_test_splitを用いると便利です。train_test_splitを用いると、ランダムに指定された割合で教師データを訓練用と評価用とに分割してくれます。以下は、80%を訓練用、残りの20%を評価用にランダムに分割する例です。

from sklearn.model_selection import train_test_split
Xtr, Xte, ytr, yte = train_test_split(Xnorm, y, train_size = 0.8, test_size = 0.2)  # 訓練用と評価用とに分割

print(len(Xtr))
print(len(Xte))
428 # 訓練用データの数
108 # 評価用データの数

関数の学習

訓練用データ \{Xtr, ytr\}を用いて、入力から出力の数値を回帰する関数を学習していきます。

scikit-learnでは、回帰手法として、以下のように直線の関数で入力 Xtrから出力 ytrを予測する線形回帰LinearRegressionを提供しています。
f:id:hirotaka_hachiya:20190528104826p:plain

以下は、LinearRegressionを用いて関数fを定義した後、fitメソッドを用いて訓練用データ \{Xtr, ytr\}に対する予測誤差を最小化するように関数fのパラメータを学習します。

from sklearn import linear_model
f = linear_model.LinearRegression()  # 関数fの定義
f.fit(Xtr, ytr)  # 関数fの学習

学習により得られた傾きと切片のパラメータは、以下のcoef_(傾き)、intercept_(切片)を用いて確認することができます。

print(f.coef_)  # 傾き
print(f.intercept_)  # 切片
[16612.13317711]  # 傾き
186474.55561352475  # 切片

販売価格SalePriceのy軸に、約18万ドル(=約1900万円)のころで交わり、敷地面積LotAreaが1フィート(=0.3048メートル)平方増加するたびに1万6千ドル(=約180万円)価格が増加するように直線が引かれていることがわかります。

関数の評価

学習した関数fの精度を評価するために、評価データ \{Xte, yte\}を用います。
以下のように、LinearRegressionのpredictメソッドを用いて Xteに対する予測 ypreを取得します。

ypre = f.predict(Xte)

そして、真の値 yteとの誤差を計算します。今回は平均絶対誤差を用います。

print("評価データの絶対誤差=", np.mean(np.abs(yte - ypre)))
評価データの絶対誤差= 55854.1884793132

予測誤差は、平均で約5万ドル(=約550万円)ほどあることがわかります。

可視化

平均的な誤差では実際には、どれくらい予測ができているのか直感的につかめません。そこで、グラフを用いて結果を可視化していきます。
まず、標準化した入力データを、逆の計算を行い、元のスケールに戻します。

Xtmp = (Xte * Xstd) + Xmean

そして、matplotlibのplotを用いて、予測値yprと真値yteの散布図をプロットします。

fig = plt.figure()

ax=fig.add_subplot(1,1,1)
        
# 予測のプロット
ax.plot(Xtmp, ypre,'.',label='predict')
        
# 真値のプロット
ax.plot(Xtmp, yte,'.',label='true')
        
ax.set_ylim([np.min(yte), np.max(yte)])  # y軸の範囲
ax.set_xlabel("LotArea")  # x軸のラベル
ax.set_ylabel("SalePrice")  # y軸のラベル

plt.tight_layout()  # グラフ間にすきまをあける
plt.show()  # グラフの表示

f:id:hirotaka_hachiya:20190528122152p:plain

scikit-learnを用いた機械学習(教師あり学習 2/3)>>