import numpy as np
import pandas as pd
import sklearn
import sklearn.datasets as ds
from sklearn.model_selection import cross_val_score, GridSearchCV
import sklearn.svm as svm
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
$x + y >1$のときtrue, それ以外はfalseになる$200\times 200$の2次元データyを作る。
X = np.random.randn(200, 2)
y = X[:, 0] + X[:, 1] > 1
# x0 + x1 > 0 のときtrue, それ以外 false => それデータとしてtrue or falseの境界をsvcで見つける
線形識別機の用意 (LinearSVC関数の利用)
# We train the classifier.
est = svm.LinearSVC()
est.fit(X, y);
識別実行のための関数定義
# We generate a grid in the square [-3,3 ]^2.
xx, yy = np.meshgrid(np.linspace(-3, 3, 500),
np.linspace(-3, 3, 500))
# This function takes a SVM estimator as input.
def plot_decision_function(est):
# We evaluate the decision function on the grid.
Z = est.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
cmap = plt.cm.Blues
# We display the decision function on the grid.
plt.figure(figsize=(5,5));
plt.imshow(Z,
extent=(xx.min(), xx.max(), yy.min(), yy.max()),
aspect='auto', origin='lower', cmap=cmap);
# We display the boundaries.
plt.contour(xx, yy, Z, levels=[0], linewidths=2,
colors='k');
# We display the points with their true labels.
plt.scatter(X[:, 0], X[:, 1], s=30, c=.5+.5*y, lw=1,
cmap=cmap, vmin=0, vmax=1);
plt.axhline(0, color='k', ls='--');
plt.axvline(0, color='k', ls='--');
plt.xticks(());
plt.yticks(());
plt.axis([-3, 3, -3, 3]);
識別の実行と図示
plot_decision_function(est);
plt.title("Linearly separable, linear SVC");
The linear SVC tried to separate the points with a line and it did a pretty good job.
1,3象限はtrue, 2、4象限はfalseとなるデータを作成し、線形識別してみる。
y = np.logical_xor(X[:, 0] > 0, X[:, 1] > 0) # 1,3象限はtrue, 2、4象限はfalse
# We train the classifier.
est = GridSearchCV(svm.LinearSVC(),
{'C': np.logspace(-3., 3., 10)});
est.fit(X, y);
print("Score: {0:.1f}".format(
cross_val_score(est, X, y).mean()))
# Plot the decision function.
plot_decision_function(est);
plt.title("XOR, linear SVC");
データ${\bf x}$ に対する非線形関数$\{{\bf\phi}_1, {\bf\phi}_2, \cdots, {\bf\phi}_M\}$を用意し、 $$ y({\bf x}) = {\bf w}^T {\bf \phi}({\bf x}) +b $$ のような、目標変数と説明変数の間に非線形な関係があるとし、係数${\bf w} = (w_1, w_2, \cdots, w_M)^T$を学習により求める。
この問題は、$k({\bf x},{\bf x'})= {\bf \phi} ({\bf x})^T{\bf \phi} ({\bf x}')$で定義されるカーネルを用いて
$$ y({\bf x}) = \sum_{n=1}^{N} a_n t_n k({\bf x}, {\bf x_n}) + b $$
の形式に変換できることが知られている。ここで$t_n$は訓練データ${\bf x_n}$に対する目標値であり、$a_n$は学習により求める係数である。
重要な(利)点は、非線形関数${\bf \phi}$を設定するのではなく、カーネル$k({\bf x},{\bf x'})$を指定することにより識別学習を行えることである。(逆に言えば関数${\bf \phi}$はどのようなものかわからない。)
Scikit-learnのSVCでは、カーネルとしては標準的にガウシアン放射基底関数(Gaussian Radial Basis Function)が用いられている。
$$ k({\bf x},{\bf x'}) = \exp ( -\gamma || {\bf x}-{\bf x'} ||^2) $$
が用いられる。パラメータ$\gamma$の値はグリッドサーチや交差検定を使って定められる。
SVC
classifier in scikit-learn uses the Radial Basis Function (RBF) kernel.y = np.logical_xor(X[:, 0] > 0, X[:, 1] > 0)
est = GridSearchCV(svm.SVC(),
{'C': np.logspace(-3., 3., 10),
'gamma': np.logspace(-3., 3., 10)});
est.fit(X, y);
print("Score: {0:.3f}".format(
cross_val_score(est, X, y).mean()))
plot_decision_function(est.best_estimator_);
plt.title("XOR, non-linear SVC");
This time, the non-linear SVC does a pretty good job at classifying these non-linearly separable points.
SVRは、関数近似の範囲を越えた様々な(数量化)説明変数を加えた回帰を解くことができるが、ここでは単純な1変数関数近似をリッジ回帰と比べてみる。
つぎのような、sin関数にノイズを載せたデータを学習させる。
データとsvrサンプルは
https://qiita.com/hrs1985/items/ba24fde9981f611cc7d8
よりとった。
データの範囲を越えた予測は困難だが、無難な値に収まっている。(べき関数へのリッジ回帰と比べてみてほしい。)
import numpy as np
import random
import matplotlib.pyplot as plt
from sklearn import svm
PI = 3.14
x_max = 8. # 予測の範囲の上限
def make_data_by_sin_gaussian():
# 0~2πまでを120等分した点を作る
X = np.array(range(120))
X = X * 6 * PI / 360
# y=sinXを計算し、ガウス分布に従う誤差を加える
y = np.sin(X)
e = [random.gauss(0, 0.2) for i in range(len(y))]
y += e
# 列ベクトルに変換する
X = X[:, np.newaxis]
return (X, y)
if __name__ == '__main__':
(x,y) = make_data_by_sin_gaussian()
# 学習を行う
svr = svm.SVR(kernel='rbf')
svr.fit(x, y)
# 回帰曲線を描く
x_plot = np.linspace(0, x_max, 10000)
y_plot = svr.predict(x_plot[:, np.newaxis])
#グラフにプロットする。
plt.scatter(x, y)
plt.plot(x_plot, y_plot)
plt.show()
基底関数を$n$次のべき関数にしてフィッティングした例
import sklearn.linear_model as lm
ridge = lm.Ridge()
x_max = 7.5
(x,y) = make_data_by_sin_gaussian()
x_tr = np.linspace(0., x_max, 200)
for deg in [3,5,8]:
ridge.fit(np.vander(x[:,0], deg +1), y)
y_ridge = ridge.predict(np.vander(x_tr, deg+1))
plt.plot(x_tr, y_ridge,
label='degree ' + str(deg))
plt.legend(loc=2)
# モデルの係数表示
print(' '. join(['%.2f' % c for c in ridge.coef_]))
plt.scatter(x, y, c='gray')
plt.xlim(0, x_max)
plt.title('Ridge Regression')