Support Vector Regressorの実装(sklearn)
概要
sklearnのSupport Vector Regressor(SVR)は主にSVR, NuSVR, LinearSVRの三種類がある。LinearSVRの方がSVRより計算が若干早く、NuSVRはSVRとLinearSVRと実装の仕方が若干違う。詳しくはこちら。今回は一般的なSVRを使用する。
注意点
今回の実装ではsklearnバージョン0.21.2を使用したが、参考文献としてはバージョン0.22のドキュメントを参考にしている点に注意してほしい。しかし、今回の実装では、バージョンによるデフォルト設定が少し違ったものの、それ以外はほとんど変わらない。
環境
sklearn 0.21.2
デフォルトパラメータ
from sklearn.svm import SVR model = SVR()
SVR(C=1.0, cache_size=200, coef0=0.0, degree=3, epsilon=0.1, gamma='auto_deprecated', kernel='rbf', max_iter=-1, shrinking=True, tol=0.001, verbose=False)
パラメータ
- kernel (rbf) : linear, poly, rbf, sigmoid, precomputedから選択可能
- linear :
- poly :
- rbf :
- sigmoid :
- degree (3) : kernelがpolyのときのみ有効。のこと。
- gamma (auto) : kernelがrbf, poly, sigmoidのときに有効。scale, auto, 数値から選択可能。のこと。
- scale : 1 / (n_features * X.var())
- auto : 1 / n_features
- coef0 (0) : kernelがpoly, sigmoidのときに有効。のこと。
- tol (1e-3) :
- C (1.0) : 正則化に使用。l2正則化を行う
- epsilon (0.1) :
実装
今回はrbfカーネルを使用する。よって、gamma, C, epsilonの3つのパラメータを決める。
データ
ボストンデータを利用する。訓練、テストデータに分離した後、スケーリングする。
from sklearn.datasets import load_boston from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler data = load_boston() x_train, x_test, y_train, y_test = train_test_split(data['data'], data['target'], test_size=0.2, random_state=0) scaler = StandardScaler() scaler.fit(data['data']) x_train = scaler.transform(x_train) x_test = scaler.transform(x_test)
モデル
from sklearn.svm import SVR model = SVR()
ハイパーパラメータチューニング
今回のハイパーパラメータはC
, epsilon
, gamma
の3つ。グリッドサーチクロスバリデーションで最適化する。5-fold cross validationをする。
n_splits = 5 params = {'C' : [1], 'epsilon' : [1], 'gamma' : ['scale']}
gamma
をまずscale
に固定して他のパラメータを調整する。グリッドサーチや1つのパラメータチューニングはRidge回帰の実装で定義されている関数(gscv, search_param1)を使う。GridsearchCV を利用しても内容はほとんど変わらない。今回は、二つのパラメータチューニングの結果をヒートマップで可視化してみる。
def ShowHeatMap(df, param1_name, param2_name): x = df.columns y = df.index score_max = df.max().max() score_min = df.min().min() fig = plt.figure(figsize=(10, 6)) ax = fig.add_subplot(111) im = ax.imshow(df, interpolation='nearest', vmin=score_min, vmax=score_max, cmap='Reds') fig.colorbar(im) ax.set_xticks(range(0, len(x))) ax.set_yticks(range(0, len(y))) ax.set_xticklabels(x) ax.set_yticklabels(y) ax.set_ylabel(f'param_{param1_name}') ax.set_xlabel(f'param_{param2_name}') plt.show()
次に、ハイパーパラメータをチューニングするパイプラインを関数で定義する。ハイパーパラメータをチューニングし、グラフを表示し、もっともよかったパラメータを自動的に更新する。
def search_param2(param1_name, param1_values, param2_name, param2_values, params): new_params = params.copy() new_params[param1_name] = param1_values new_params[param2_name] = param2_values print(f'set new_params: {new_params}') results = gscv([x_train, y_train], new_params) cv_score_li = results['validation_score_mean'] best_index = cv_score_li.index(max(cv_score_li)) print(f"cv score: {results['validation_score_mean'][best_index]:.2f}+-{results['validation_score_std'][best_index]:.3f}") print(f"best params: {results['params'][best_index]}") scores = results['validation_score_mean'] param1_li = results[f'param_{param1_name}'] param2_li = results[f'param_{param2_name}'] cv_data = np.stack([scores, param1_li, param2_li], axis=1) cv_data = sorted(cv_data, key=lambda x: (x[1], x[2])) scores = np.array(cv_data).T[0].astype(float) x = sorted(new_params[param1_name]) y = sorted(new_params[param2_name]) scores = scores.reshape((len(x),len(y))) df = pd.DataFrame(scores, columns=y, index=x) display(df ) ShowHeatMap(df, param1_name, param2_name) params[param1_name] = [results['params'][best_index][param1_name]] params[param2_name] = [results['params'][best_index][param2_name]]
実行する。
search_param2('C', [0.01, 0.1, 1, 10, 100, 1000], 'epsilon', [0, 0.01, 0.1, 1, 10, 100], params)
set new_params: {'C': [0.01, 0.1, 1, 10, 100, 1000, 10000], 'epsilon': [0, 0.01, 0.1, 1, 10, 100], 'gamma': ['scale']} cv score: 0.87+-0.041 best params: {'C': 100, 'epsilon': 1, 'gamma': 'scale'}
C
が100、epsilon
が1で最も良い結果が出た。次に、gamma
をsearch_param1を使って検証してみる。
search_param1('gamma', [0, 0.001, 0.01, 0.1, 1, 10, 100, 1000], params )
set new_params: {'C': [100], 'epsilon': [1], 'gamma': [0, 0.001, 0.01, 0.1, 1, 10, 100, 1000]} cv score: 0.86+-0.031 best params: {'C': 100, 'epsilon': 1, 'gamma': 0.1}
`
gamma`は0.01がベストであった。
訓練と予測
#train for k, v in params.items(): params[k] = v[0] model.set_params(**params) model.fit(x_train, y_train) #predict y_pred = model.predict(x_test)
結果と分析
決定係数は組み込み関数で計算できる。
r2 = model.score(x_test, y_test)
print(r2)
0.768769885637091
予測した値をプロットする。
import matplotlib.pyplot as plt fig = plt.figure(figsize=(6,6)) ax = fig.add_subplot(111) ax.scatter(y_test, y_pred) ax.set_xlabel('y_test') ax.set_ylabel('y_pred') plt.show()
参照文献
scikit-learn 0.22 sklearn.svm.SVR
scikit-learn 0.22 1.4.Support Vector Machines