下校時刻

メモ、読んだ本のまとめメモ、考えたことのメモ、その他のメモなどが書いてあるブログです(twitter: @hoture6)

「Python Machine Learning」Ch. 10(回帰について)まとめ

いままではすべて分類の話だったのですが、Ch10は回帰について書いてあります。


重要な特徴量の可視化

重回帰分析では説明変数がめちゃくちゃ多い場合があるので、どの変数が重要なのか、依存性はどうなっているかをまずは可視化したい。方法は、

の2種類。

散布図行列

seaborn.pairplotを使う。対角成分では、説明変数の分布をヒストグラムでも示してくれる。

import seaborn as sns

sns.pairplot(df)

相関係数行列

2つの変数の関係が線形に近い場合は、相関係数でその関係が記述できる。

cm = df.corr()
# cm = np.corrcoef(df.values.T)

sns.heatmap(cm, cbar=True, annot=True, square=True, xticklabels=cols, yticklabels=cols)

回帰分析の実行

いろいろな手法がある。今回行うのは、

線形回帰

ふつうの方法。損失関数を誤差平方和で表し、これを減らしていく(最小自乗法)。

from sklearn.linear_model import LinearRegression

lr = LinearRegression()
lr.fit(X, y)

lr.coef_[0] # 傾き
lr.intercept_ # 切片

RANSAC

通常の線形回帰は外れ値に弱いという弱点がある。外れ値の影響を減らすことのできる手法がRANSAC。以下の手順で回帰を行う。

  1. サンプルのうち何個かを'inliers'として選び、回帰を行う
  2. すべてのサンプルのうち、1の回帰直線に近いサンプルのみを'inliers'とする
  3. 2で選ばれた'inliers'に対して回帰を行う
  4. 基準を満たすまで2と3を繰り返す。もし一定回数繰り返しても基準を満たさない場合、1からやり直す
from sklearn.linear_model import RANSACRegressor

ransac = RANSACRegressor(LinearRegression(), max_trials=100, min_samples=50, residual_metric=lambda x: np.sum(np.abs(x), axis=1), residual_threshold=5.0)
ransac.fit(X, y)

X_fit = np.arange(3, 10, 1)
y_fit = ransac.predict(X_fit[:, np.newaxis])

# 以下のマスクでinlierとoutlierを分けて扱える
inlier_mask = ransac.inlier_mask_
outlier_mask = np.logical_not(inlier_mask)

正則化つき回帰

overfittingにならないように、大きすぎる回帰係数にペナルティをつける手法がある。すなわち、ふつうの回帰では損失関数は誤差平方和のみだが、それに「回帰係数の大きさ」を加える。この大きさの測り方によって、以下のような手法がある。

Ridge(L2正則化

$$J(w) = \sum_{i} (y^{(i)} - \hat{y}^{(i)}) + \lambda \sum_{j} {w_{j}}^{2}$$

from sklearn.linear_model import Ridge

ridge = Ridge(alpha=1.0)
ridge.fit(X, y)

LASSO(L1正則化

L1正則化なので、特徴量を減らす効果がある。

$$J(w) = \sum_{i} (y^{(i)} - \hat{y}^{(i)}) + \lambda \sum_{j} |w_{j}|$$

from sklearn.linear_model import Lasso

lasso = Lasso(alpha=1.0)
lasso.fit(X, y)

Elastic Net

RidgeとLASSOの中間(L1のL2の項を両方含む)。

$$J(w) = \sum_{i} (y^{(i)} - \hat{y}^{(i)}) + \lambda_{1} \sum_{j} |w_{j}| + \lambda_{2} \sum_{j} {w_{j}}^{2}$$

from sklearn.linear_model import ElasticNet

elnet = ElasticNet(alpha=1.0, l1_ratio=0.5)
elnet.fit(X, y)

多項式回帰

いままでは

$$y = w_{0} + w_{1} x$$

のような回帰を考えてきたが、yとxが線形の関係でないときは、

$$y = w_{0} + w_{1} x + w_{2} x^{2} + \cdots$$

のような多項式回帰を考える。ここで、$y$は$x$に対しては非線形だが、$w$に対しては線形なので、相変わらず線形回帰の枠組みが使える。当然、次数を上げるごとにモデルが複雑になり、overfittingの可能性が高まるので注意。

from sklearn.preprocessing import PolynomialFeatures

quad = PolynomialFeatures(degree=2)
x_quad = quad.fit_transform(x)

pr = LinearRegression()
pr.fit(x_quad, y)

x_fit = np.arange(250, 600, 2).reshape(-1, 1)
y_fit = pr.predict(quad.fit_transform(x_fit))

Random Forest

非線形な関係は、Random Forestによる回帰でも扱える。基本的なアルゴリズムは分類のタスクと同じで、決定木でラベルを貼り付ける代わりに実数値を与えると考えると良さそう。分類ではエントロピーを最小にするように分割したが、回帰では誤差平方和が最小になるように分割する。

from sklearn.ensemble import RandomForestRegressor

tree = DecisionTreeRegressor(max_depth=2)
tree.fit(x, y)

x_fit = np.arange(250, 600, 2).reshape(-1, 1)
y_fit = tree.predict(x_fit)