LoginSignup

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 5 years have passed since last update.

【読書会】python機械学習プログラミング_10章

Last updated at Posted at 2017-04-16

回帰分析

回帰モデルは、連続値をとる目的変数を予測するために使用される
例)
・アイスが何個売れるか予測
・ある人の給与がいくらかを予測

1,線形回帰モデルとは
2,使用データの特性を可視化する
3,勾配降下法を使った回帰
4,RANSACを使ったロバスト回帰
5,線形回帰モデルの性能評価
6,多項式回帰モデル
7,非線形関係のモデリング

1,線形回帰モデルとは

線形回帰とは単一の特徴量(x)と連続値の応答(y)との関係をモデルとして表現すること
例)気温(x)とアイスの売り上げ(y)


y=W_0 + W_1x

10_01.png

重みと切片を調整することで、「サンプル点を通過する直線のうち、最も適合するものを見つけ出す」

2,使用データの特性を可視化する

Housingデータセット ボストン近郊の住宅情報データセット(サンプル数 506個)

データセットをインポート
最初の5行を取得する

import pandas as pd

df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/'
                 'housing/housing.data',
                 header=None,
                 sep='\s+')

df.columns = ['CRIM', 'ZN', 'INDUS', 'CHAS', 
              'NOX', 'RM', 'AGE', 'DIS', 'RAD', 
              'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
df.head()

10_02.png

このデータの特性を可視化する

探索的データ解析(EDA)は機械学習モデルのトレーニングを行う前の重要なステップとして推奨される

まず、「散布図行列」を作成する
散布図行列を利用すれば、データセットの特徴量ペアに対する相対関係を一つの平面で可視化できる
散布図行列のプロットには、seabornライブラリのpiplot関数を使用する
seaborunでは、matplotlibに基づいて統計グラフを描画するためのpythonライブラリ


import matplotlib.pyplot as plt
import seaborn as sns


sns.set(style='whitegrid', context='notebook')
cols = ['LSTAT', 'INDUS', 'NOX', 'RM', 'MEDV']

sns.pairplot(df[cols], size=2.5)
plt.tight_layout()
# plt.savefig('./figures/scatter.png', dpi=300)
plt.show()

10_03.png

これを見ることで
・データの分布
・外れ値
・カラムとカラムの関係性

カラムとカラムの関係性を見るには、相関行列を作成して見るのがよい
相関行列とは、ピアソンの積率相関係数を成分とする正方行列である

pythonでは
Numpyのcorrcoef関数によってピアソンの積率相関係数を計算する
そしてseabornのheatmap関数を使って相関行列をヒートマップとしてプロットする

import numpy as np


cm = np.corrcoef(df[cols].values.T)
sns.set(font_scale=1.5)
hm = sns.heatmap(cm,
                 cbar=True,
                 annot=True,
                 square=True,
                 fmt='.2f',
                 annot_kws={'size': 15},
                 yticklabels=cols,
                 xticklabels=cols)

# plt.tight_layout()
# plt.savefig('./figures/corr_mat.png', dpi=300)
plt.show()

これによって便利な集計グラフがもうひとつ得られる

3,scikit-learnによる回帰

scikit-learnのLinearRegressionオブジェクトは標準化されていない変数に適応する
LIBLINEARライブラリや非常に最適化されたアルゴリズムを利用している

from sklearn.linear_model import LinearRegression

X = df[['RM']].values
y = df['MEDV'].values
slr = LinearRegression()
slr.fit(X, y)
y_pred = slr.predict(X)
print('Slope: %.3f' % slr.coef_[0])
print('Intercept: %.3f' % slr.intercept_)

Slope: 9.102
Intercept: -34.671

結果をプロットしてみる

lin_regplot(X, y, slr)
plt.xlabel('Average number of rooms [RM]')
plt.ylabel('Price in $1000\'s [MEDV]')
plt.tight_layout()
# plt.savefig('./figures/scikit_lr_fit.png', dpi=300)
plt.show()

10_07.png

4,RANSACを使ったロバスト回帰

ロバスト回帰
外れ値の影響を抑えた上で回帰を実行する手法の総称
基本的な考え方としては、外れ値の重みを小さくする

http://qiita.com/smurakami/items/14202a83bd13e55d4c09

RANSACとは、外れ値を無視して法則性を推定する方法のこと

例えばこんなグラフ
442eb997-9ae8-4cac-846e-074d3730967f.png

外れ値がとても多い
なのでこれで普通に回帰すると

3858b9fd-437f-0d8c-ee09-723947d1546c.png

こんなところに線が引かれる
なので外れ値を無視してやると(RANSAC)

d76b838f-ccb9-09a6-3cf5-a4c5eb3e4918.png

うまくできる

from sklearn.linear_model import RANSACRegressor

if Version(sklearn_version) < '0.18':
    ransac = RANSACRegressor(LinearRegression(), 
                             max_trials=100, 
                             min_samples=50, 
                             residual_metric=lambda x: np.sum(np.abs(x), axis=1), 
                             residual_threshold=5.0, 
                             random_state=0)
else:
    ransac = RANSACRegressor(LinearRegression(), 
                             max_trials=100, 
                             min_samples=50, 
                             loss='absolute_loss', 
                             residual_threshold=5.0, 
                             random_state=0)


ransac.fit(X, y)
inlier_mask = ransac.inlier_mask_
outlier_mask = np.logical_not(inlier_mask)

line_X = np.arange(3, 10, 1)
line_y_ransac = ransac.predict(line_X[:, np.newaxis])
plt.scatter(X[inlier_mask], y[inlier_mask],
            c='blue', marker='o', label='Inliers')
plt.scatter(X[outlier_mask], y[outlier_mask],
            c='lightgreen', marker='s', label='Outliers')
plt.plot(line_X, line_y_ransac, color='red')   
plt.xlabel('Average number of rooms [RM]')
plt.ylabel('Price in $1000\'s [MEDV]')
plt.legend(loc='upper left')

plt.tight_layout()
# plt.savefig('./figures/ransac_fit.png', dpi=300)
plt.show()

10_08.png

6,多項式回帰モデル

ここまでの内容は、説明変数と目的変数が線形であることを前提としていた
この前提が外れる場合には、多項式回帰モデルを使用する、という方法がある

y=w_o + w_1x + w_2x^2 + ... + w_dx^d

scikit-learnのPolymialFeatures変換器クラスを使用して、説明変数が一つだけの単縦な回帰問題に対して2次の項を追加し、多項式回帰と線形回帰を比較する

X = np.array([258.0, 270.0, 294.0, 
              320.0, 342.0, 368.0, 
              396.0, 446.0, 480.0, 586.0])[:, np.newaxis]

y = np.array([236.4, 234.4, 252.8, 
              298.6, 314.2, 342.2, 
              360.8, 368.0, 391.2,
              390.8])
from sklearn.preprocessing import PolynomialFeatures

lr = LinearRegression()
pr = LinearRegression()
quadratic = PolynomialFeatures(degree=2)
X_quad = quadratic.fit_transform(X)
# fit linear features
lr.fit(X, y)
X_fit = np.arange(250, 600, 10)[:, np.newaxis]
y_lin_fit = lr.predict(X_fit)

# fit quadratic features
pr.fit(X_quad, y)
y_quad_fit = pr.predict(quadratic.fit_transform(X_fit))

# plot results
plt.scatter(X, y, label='training points')
plt.plot(X_fit, y_lin_fit, label='linear fit', linestyle='--')
plt.plot(X_fit, y_quad_fit, label='quadratic fit')
plt.legend(loc='upper left')

plt.tight_layout()
# plt.savefig('./figures/poly_example.png', dpi=300)
plt.show()

10_10.png

線形回帰より多項式回帰よりもうまく補足していることがわかる

7,非線形関係のモデリング

決定木による回帰

前述のグローバルな線形回帰モデルや多項式回帰モデルとは対照的に
区分線形関数の和として考えることができる
つまり、決定木アルゴリズムを使って入力空間をより「管理しやすい」小さな領域に分割する

decision-tree-regression-tree-rpart-cp-prune.png

この領域はこの分布
その領域はこの分布
というふうに決めていく

ひとまず決定木でやってみる

from sklearn.tree import DecisionTreeRegressor

X = df[['LSTAT']].values
y = df['MEDV'].values

tree = DecisionTreeRegressor(max_depth=3)
tree.fit(X, y)

sort_idx = X.flatten().argsort()

lin_regplot(X[sort_idx], y[sort_idx], tree)
plt.xlabel('% lower status of the population [LSTAT]')
plt.ylabel('Price in $1000\'s [MEDV]')
# plt.savefig('./figures/tree_regression.png', dpi=300)
plt.show()

10_13.png

これを決定木からランダムフォレストを使うことできる

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up