0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【ラビットチャレンジ】 Stage2 - 機械学習

Posted at

ラビットチャレンジ

ラビットチャレンジはE資格の受験に必要な協会認定講座のプログラムです。
ラビットチャレンジでは認定プログラムを修了してE資格の受験資格を習得するために、指定のレポートとテストで合格点を取得しなければなりません。

今回はStage2機械学習についてまとめます。

  • Stage1 応用数学
  • Stage2 機械学習
  • stage3 深層学習前編(day1, day2)
  • stage4 深層学習後編(day3, day4)

第1章 線形回帰

機械学習

・タスク$T$を性能指標$P$で測定し、その性能が経験$E$により改善される場合、タスク$T$および性能指標$P$に関して経験$E$から学習する。(トムミッチェル)
・対義的にはルールベースモデルとなります。
 - タスク:$T$
 - 性能指標:$P$
 - 経験:$E$

回帰問題

・ある入力(離散 or 連続)から連続する出力値を予測します。
・直線で予測する場合に線形回帰(Linner)となり曲線で予測する場合に非線形回帰(Rigde)となります。
 - 入力:説明変数、特徴量(m=1の場合はスカラー)
 - 出力:目的変数(スカラー値)

・説明変数は縦ベクトルですが、通常転値して表記します。
 $x=(x1, x2, ...)$

線形回帰モデル

・教師あり学習です。
・教師データ:説明変数$x$に対する目的変数$y$が$n$個存在します。
・入力と$m$次元パラメータの線形結合を出力するモデルです。
・慣例として予測値にはハットを付けます。
  $\hat y = w^tx+w_0$

線形結合

・入力とパラメータの内積で表します。
・入力ベクトルと未知のパラメータの各要素を掛け足したものです。
・入力ベクトルとその線形結合に加え切片($y$軸との交点)も足します。($w_0$)
・入力ベクトルが多次元でも出力は1次元(スカラ)となります。

モデルのパラメータ

・モデルに含まれる推定すべき未知のパラメータです。
・特徴量が予測値に対してどのように影響を与えるかを決定する重みの集合です。

学習用データ

・機械学習モデルの学習に利用するデータです。

検証用データ

・学習済みモデルの精度を検証するためのデータです。
・未知のデータに対しての汎化性能を測るために分割します。

平均二乗誤差

・データとモデル出力の二乗誤差の和です。
・データ既知の値であるためパラメータのみに依存します。

  • 平均二乗誤差:$MSE_{(train)}$
  • $n_{(train)}$:学習データ数
  • $\hat y_i^{(train)}$:期待値
  • $y_i^{(train)}$:実際の値
MSE_{(train)} = \frac{1}{n_{(train)}}\sum_{i=1}^{n_{(train)}}(\hat y_i^{(train)}-y_i^{(train)})^2

最小二乗法

・学習データの平均二乗誤差を最小とするパラメータを探索します。
・学習データの平均二乗誤差の最小化は、その誤差が0になる点で求めることができます。

単回帰モデル

・説明変数が1次元のモデルです

  • 目的変数:y
  • $w_0$:切片(未知)
  • $w_1$:回帰変数(未知)
  • $x_1$:説明変数
  • $\epsilon$:誤差(イプシロン)
y=w_0+w_1x_1+\epsilon

連立方程式

・それぞれのデータをモデル式に当てはめるとn個の式ができます。

y_1=W_0+W_1x_1+\epsilon_1\\
y_n=W_0+W_1x_n+\epsilon_n\\
y = Xn + \epsilon

線形回帰モデル

・説明変数が多次元です。
・単回帰は直線、重回帰は曲線となります。

  • 目的変数:y
  • $w_0$:切片(未知)
  • $w_1$:回帰変数(未知)
  • $x_1$:説明変数
  • $w_2$:回帰変数(未知)
  • $x_2$:説明変数
  • $\epsilon$:誤差(イプシロン)
y=w_0+w_1x_1+w_2x_2+\epsilon

MSE

・$MSE$を最小にするような$W$を求めます。

MSE_{train} = \frac{1}{n_{train}}\sum_{i=1}^{n_{train}}(\hat y_i^{train}-y_i^{train})^2\\
\hat W=argmin MSE_{train}

・$MSE$を$w$に関して微分したものが$0$となる$W$

\frac{\partial}{\partial w}{\frac{1}{n_{(train)}}\sum_{i=1}^{n_{(train)}}(\hat y ^{(train)}-y^{(train)})^2 } = 0

回帰係数

\hat w = (X^{(train)T}X^{(train)})^{-1}X^{(train)T}y^{(train)}

予測値

\hat y = X(X^{(train)T}X^{(train)})^{-1}X^{(train)T}y^{(train)}

・平均二乗誤差の最小値と最尤法の最大値は一致します。

非線形回帰モデル

基底展開法

・基底関数と呼ばれる既知の非線形関数とパラメータベクトルの線形結合です。
・未知のパラメータは線形回帰モデルと同様に最小二乗法や最尤法により推定します。

y_i=f(x_i)+\epsilon_i
y_i=w_0+\sum_{i=1}^mw_j\phi(x_i)+\epsilon_i

・基底関数には「多項式関数」「ガウス型基底関数」「スプライン関数」「Bスプライン関数」などがあります。

多項式

\phi j=xj

ガウス型基底

\phi j(x)=exp{\frac{(x-\mu_j)^2}{2hj}}

二次元ガウス基底

\phi j(x)=exp{\frac{(x-\mu_j)^T(x-\mu_j)}{2hj}}

未学習と過学習

・学習データに対して十分小さな誤差が得られない場合には、未学習となります。
 - 学習データを増やすことで防ぐことができます。
・小さな誤差は得られたが、テストデータとの誤差が大きい場合には、過学習となります。
 - 不要な基底関数を削除して表現力を抑止することで過学習を防ぐことができます。
 - 正則法を利用して表現力を抑止することで過学習を防ぐことができます。

正則化法(罰則化法)

・モデルの複雑さに伴って、その値が大きくなります
 - 正則化項(罰則項)を課した関数を最小化

S_r=(y-\phi w)^T(y-\phi w)+\gamma R(w)

Ridge推定量

・L2ノルムを利用します。
・縮小推定。
・円形でパラメータを0に近づけるよう推定します。

Lasso推定量

・L1ノルムを利用します。
・スパース推定。
・ひし形でパラメータを正確に0に推定します。

汎化性能

・学習に使用した入力だけでなく、これまで見たことのない入力に対する予測性能です。
・汎化性能が低い場合には学習したものしか予測できなくなります。(過学習)

MSE_{test} = \frac{1}{n_{test}}\sum_{i=1}^{n_{test}}(\hat y_i^{test}-y_i^{test})^2\\

ホールドアウト法

・有限のデータを学習用とテストに分離します。
・学習用のデータ数を多くすると学習精度は上がりますが、性能評価の精度は下がります。
・テスト用のデータを多くすると学習制度が下がります。

クロスバリデーション

・交差検証。
・データをイテレータごとに学習用とテスト用に分類します。
・イテレータごとの結果の平均値をCV値と言います。

ロジスティック回帰モデル

・ある入力からクラスに分類する
・入力はm次元のベクトル
・出力は0or1

・説明変数$x=(x_1, x_2, ...x_m)^T∈R^m$
・目的変数$y∈{0,1}$
・教師データ${(x_i,y_i)_{ji}}=1,...n$

ロジスティック線形回帰モデル

・分類問題を解くための教師あり機械学習モデル
・入力とm次元パラメータの線形結合をシグモイド関数に入れる

・パラメータ$w=(w_1, w_2...w_m)^T∈R^m$
・線形結合:$\hat y = w^Tx + w_0=\sum_{j=1}^mw_jx_j+w_0$

シグモイド関数

・入力は実数・出力は必ず0~1
・パラメータαが変わるとシグモイド関数の形が変わる

\sigma(x)=\frac{1}{1+exp(-\sigma x)}

・シグモイド関数の微分は地震で表現することが可能

\frac{\partial \sigma(x)}{\partial x}=\frac{\partial}{\partial x}(\frac{1}{1+exp(-\sigma x)}) = a\sigma(x)(1-\sigma(x))

最尤推定

P(Y=1\mid x)⁼\sigma(w_0+w_1x_1+...w_mx_m)

説明変数の実現値が与えられた際にY=1になる確率

P(Y=1\mid x)⁼\sigma(w_0+w_1x_1)

データYは確率が0.5以上なら1,0.5未満なら0

ベルヌーイ分布

・コイン投げは1/2のはずだが、いかさまコインではそうはならない
・いかさま具合をパラメータとする

P(y)⁼p^y(1-p)^{1-y}

Y= 0, 1の確率をまとめて表現している

Y=0の場合 p^0(1-p)^{1} = 1-p\\
Y=1の場合 p^1(1-p)^{0} = p

同時確率

・あるデータが得られた時にそれが同時に得られる確率
・確率変数が独立している場合にそれぞれの確率の掛け算となる
・コイン投げの場合、前回の結果は今回に関係ないため独立

総乗

$\prod$:πの大文字
・総和を表すΣのように全ての値を掛け合わす

\sum_{k=1}^3ak = a_1+a_2+a_3\\
\prod_{k=1}^3ak = a_1\times a_2\times a_3

尤度関数

・$1$回の試行

P(y)⁼p^y(1-p)^{1-y}

・$n$回の試行

P(y_1,y_2,...y_nj)=\prod_{i=1}{n}p^{y_i}(1-p)^{1-y_n}

・$n$回のデータが得られた際の尤度関数

P(y_1,y_2,...y_nj)=\prod_{i=1}{n}p^{y_i}(1-p)^{1-y_n}

・データを固定し、パラメータを変化させます。
・尤度関数を最大化するパラメータを選ぶ推定方法を尤度推定といいます。

シグモイド関数

P(Y=1\mid x)=\sigma(w_0+w_1x_1)

ベルヌーイ分布

P(y)=p^y(1-p)^{1-y}

・ロジスティック回帰モデルの最尤推定

P(Y=y_1\mid x_1)=p_1^{y_1}(1-p)^{1-y}=\sigma(w^Tx_1)^{y_1}(1-\sigma(w^Tx_1))^{1-y}
P(y_1,y_2,...y_n\mid w_0, w_1, ...w_n)=\prod_{i=1}^np_i^{y_i}(1-p_i)^{1-y_i}\\
=\prod_{i=1}^n\sigma(w^Tx_i)^{y_i}(1-\sigma(w^Tx_i))^{1-y_i}
=L(w)

・尤度関数はパラメータのみに依存します。
・対数をとると便分の計算が簡単です。
「尤度関数にマイナスをかけたものを最小化することで最小二乗法の最小化と合わせる」

E(w_0, w_1...w_m)=-logL(w_0, w_1...w_n)

勾配降下法

・反復学習によりパラメータを逐次的に更新します。
・パラメータを更新するのに$N$子全てのデータに対する輪を求める必要があります。
 ⇒ メモリが足りない、計算が莫大になる
 ⇒ 確率的勾配降下法を利用

確率的勾配降下法(SDG)

・データを一つずつランダムに選んでパラメータを更新します。
・パラメータを$1$回更新する計算量で$n$回更新できます。

w(k+1)=w^k+\eta(y_i-p_i)xi

$\eta$
・学習係数
・歩幅を表し、$\eta$で決められた値に従って次に移動する

混合行列

検証用データ:$Positive$ 検証用データ:$Negative$
予測結果:$Positive$ 真陽性 $TP$(実際に正しいものを正しいと予測) 偽陽性 $FP$(実際に正しくないものを正しいと予測)
予測結果:$Negative$ 偽陽性 $FN$(実際に正しいものを正しくないと予測) 真陰性 $TN$(実際に正しくないものを正しくないと予測)

再現率(Recall)

・実際に$Positive$な結果の中から$Positive$と予測できる割合。
・誤り($FP$)があっても抜け漏れは少ない。

\frac{TP}{TP+FN}

適合率(Precision)

・モデルがポジティブと良くしたものの中から実際に$Positive$である割合です。
・見逃しが多くても($FN$)より正解な予測です。

F値

・$Precision$と$Recall$の調和平均です。

主成分分析

・多変量データの持つ構造をより少数個の指標に圧縮できます。
・学習データ

x_i=(x_{i1}, x_{i2}, ..., x_{im})∈R^m

・平均

\bar x=\frac{1}{n}sum_{i=1}^nx_i

・データ行列

\bar X=(x_1-\bar x, ...x_n-\bar x)^T

・分散共分散行列

\sum=(Var(\bar x)=\frac{1}{n}\bar X^T \bar X

・線形変換後のベクトル

S_j=(S_{1j}-S_{nj})^T=\bar X a_j

線形返還後の分散

Var(S_j)=\frac{1}{n}S_j^TS_j=\frac{1}{n}(\bar Xa_j)^T(\bar Xa_j)\\
=\frac{1}{n}a_j^T\bar X^T \bar X a_j\\
=a_j^TVar(\bar X)a_j

・ラグランジュ関数を微分して最適解を求めます。

\frac{\partial E(a_j)}{\partial a_j}=2Var(\bar X)a_j - 2\lambda a_j = 0\\
Var(\bar X)a_j = \lambda a_j

・射影先の分散は固有値と一致します。

寄与率

・全分散の中から主成分の分散率です。

累積寄与率

・第1-k主成分まで圧縮した際の情報損失量の割合です。

C_k = \frac{\lambda_k}{\sum_{i = 1}^m\lambda_i}
r_k = \frac{\sum_{j=1}^k\lambda_j}{\sum_{m = 1}^m\lambda_i}

K近傍法

・最近傍のデータをK個とってきて、それらが最も多く所属するクラスに識別
・例えばK=3なら順番に近い3つのデータを見て最も多いクラスに分類する

k-平均法(k-means)

・教師なし学習
・クラスタリング手法
・あたら得られたデータをk個のクラスタに分類する

  1. 各クラスタの中心の初期値を設定する
  2. 各データ点と各クラスタの中心との距離を計算し、最も近いクラスタを割り当てる
  3. 各クラスの平均ベクトル(中心)を求める
  4. 2~3を繰り返す
    ※初期値が近いとうまくクラスタリングできない

最尤推定

・あるデータが得られた時それが同時に得られる確率を同時確率といいます。
・確率変数が独立であることを仮定すると、それぞれの確率の掛け算となります。

$n$回

P(y_1, y_2...y_{n}p)=\prod_{i=1}{n}p^{y_1}(1-p)^{1-y_i}

結果の$y$を固定するとパラメータ$P$を求めることができます。⇒尤度関数

P(Y=y_1\mid x_1)

$x_1$を与えたときに$Y$が$y1$になる確率

SVM

・教師あり学習の手法の一つです。
・分類でよく使用されます。
・データの境界線を引きます。
・Aグループ内でBに一番近い点とBグループ内でAに一番近いデータをサポートベクトルといいます。
・サポートベクトルに平行線を引き、その線の距離が一番大きくなるようにします。
・境界線とサポートベクトルの距離をマージンといいマージンを最大化することを目的とします。

ソフトマージン
・ある程度の間違いを認めることで線形分離します。

カーネル法
・線形分離できない場合に線形分離できる空間に変える手法です。

点と直線の距離
・点$(x_0,y_0)$と直線$ax + by + c = 0$の距離は以下の式で表されます。

\frac{(ax_0+by_0+c)}{\sqrt{a^2+b^2}}

点と平面の距離
・点$(x_0,y_0,z_0)$と直線$ax = by + cz + d= 0$の距離は以下の式で表されます。

\frac{(ax_0+by_0+cz_0+d)}{\sqrt{a^2+b^2+c^2}}

線形回帰モデル-ハンズオン

・ボストンの住宅データセットを線形回帰モデルで分析する。
・部屋数が4で犯罪率が0.3の物件の値段はいくらになるのか調べる。

from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression
from pandas import DataFrame
import numpy as np

boston = load_boston()

# 説明変数をdataに設定し、feature_namesをヘッダーに設定
df = DataFrame(data = boston.data, columns = boston.feature_names)

# 目的変数を設定
df['PRICE'] = np.array(boston.target)

'''
 [課題]
 部屋数が4で犯罪発生率が0.3の物件の値段を求める
 部屋数:RM = 4
 犯罪発生率:CRIM = 0.3
'''
data = df.loc[:, ['RM', 'CRIM']].values
target = df.loc[:, 'PRICE'].values

# オブジェクトの作成
model = LinearRegression()

# fit関数でパラメータ推定
model.fit(data, target)

# 部屋数[4]、犯罪発生率[0.3]を設定
ret = model.predict([[4, 0.3]])

print(ret)

# 出力結果:[4.24007956]

1,000$単位なので答えは4,240$

非線形回帰モデル-ハンズオン

ランダムなノイズを加えた非線形データを作成

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

sns.set()
sns.set_style("darkgrid", {'grid.linestyle': '--'})
sns.set_context("paper")

n=100
def true_func(x):
    z = 1-48 * x + 218 * x ** 2 - 315 * x ** 3 + 145 * x ** 4
    return z 

def linear_func(x):
    z = x
    return z 

data = np.random.rand(n).astype(np.float32)
data = np.sort(data)
target = true_func(data)

# ノイズを加える
noise = 0.5 * np.random.randn(n) 
target = target  + noise

plt.scatter(data, target)
plt.title('NonLinear Regression')
plt.legend(loc=2)
plt.show()

結果
Fig1.png

線形回帰モデル

from sklearn.linear_model import LinearRegression

clf = LinearRegression()
data = data.reshape(-1,1)
target = target.reshape(-1,1)
clf.fit(data, target)

p_lin = clf.predict(data)

plt.scatter(data, target, label='data')
plt.plot(data, p_lin, color='darkorange', marker='', linestyle='-', linewidth=1, markersize=6, label='linear regression')
plt.legend()
print(clf.score(data, target))
plt.show()

結果
Fig2.png

KernekRidge

from sklearn.linear_model import LinearRegression

clf = LinearRegression()
data = data.reshape(-1,1)
target = target.reshape(-1,1)
clf.fit(data, target)

p_lin = clf.predict(data)

plt.scatter(data, target, label='data')
plt.plot(data, p_lin, color='darkorange', marker='', linestyle='-', linewidth=1, markersize=6, label='linear regression')
plt.legend()
print(clf.score(data, target))
plt.show()

結果
Fig3.png

RBFカーネルの場合

from sklearn.kernel_ridge import KernelRidge

clf = KernelRidge(alpha=0.0002, kernel='rbf')
clf.fit(data, target)

p_kridge = clf.predict(data)

plt.scatter(data, target, color='blue', label='data')

plt.plot(data, p_kridge, color='orange', linestyle='-', linewidth=3, markersize=6, label='kernel ridge')
plt.legend()
plt.show()

結果
Fig4.png

ガウス型基底

from sklearn.metrics.pairwise import rbf_kernel
from sklearn.linear_model import Ridge

kx = rbf_kernel(X=data, Y=data, gamma=50)
# KX = rbf_kernel(X, x)

# clf = LinearRegression()
clf = Ridge(alpha=30)
clf.fit(kx, target)

p_ridge = clf.predict(kx)

plt.scatter(data, target,label='data')
for i in range(len(kx)):
    plt.plot(data, kx[i], color='black', linestyle='-', linewidth=1, markersize=3, label='rbf', alpha=0.2)

plt.plot(data, p_ridge, color='green', linestyle='-', linewidth=1, markersize=3,label='ridge regression')

print(clf.score(kx, target))
plt.show()

結果
Fig5.png

Lasso

from sklearn.metrics.pairwise import rbf_kernel
from sklearn.linear_model import Lasso

kx = rbf_kernel(X=data, Y=data, gamma=5)

lasso_clf = Lasso(alpha=10000, max_iter=1000)
lasso_clf.fit(kx, target)

p_lasso = lasso_clf.predict(kx)

plt.scatter(data, target)

plt.plot(data, p_lasso, color='green', linestyle='-', linewidth=3, markersize=3)

print(lasso_clf.score(kx, target))
plt.show()

結果
Fig6.png

ロジスティック回帰モデル-ハンズオン

・タイタニックの乗客データを利用しロジスティック回帰モデルを作成
・特徴量抽出を行う
・年齢が30歳で男の乗客は生き残れるのか?

import pandas as pd
from sklearn.linear_model import LogisticRegression

# タイタニックデータの読み込み(CSV)
titanic_df = pd.read_csv('./titanic_train.csv')

# 欠損値データの補完
titanic_df['AgeFill'] = titanic_df['Age'].fillna(titanic_df['Age'].mean())

# 性別を女性0,男性1に変換
titanic_df['Gender'] = titanic_df['Sex'].map({'female':0, 'male':1}).astype(int)

data = titanic_df.loc[:, ['AgeFill', 'Gender']].values
label = titanic_df.loc[:,['Survived']].values

model = LogisticRegression()
model.fit(data, label)

print('30歳男性:'+str(model.predict([[30, 1]])))
print('30歳女性:'+str(model.predict([[30, 0]])))

30歳男性は生き残れない

主成分分析-ハンズオン

・乳がん検査データを利用しロジスティック回帰モデルを作成。
・主成分を利用し、2次元空間上に次元圧縮する。
・32次元のデータを2次元上に次元圧縮した際に、うまく判別できるかを確認する。

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegressionCV
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA

# 乳がんデータの読み込み
cancer_df = pd.read_csv('cancer.csv')

# 目的変数の抽出
y = cancer_df.diagnosis.apply(lambda d:1 if d == 'M' else 0)
cancer_df.drop('Unnamed: 32', axis=1, inplace = True)
print('cancer df shape:{}'.format(cancer_df.shape))

# 説明変数の抽出
X = cancer_df.loc[:, 'radius_mean':]

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
logistic = LogisticRegressionCV(cv = 10, random_state = 0)
logistic.fit(X_train_scaled, y_train)

# 検証
print('Train score:{:.3f}'.format(logistic.score(X_train_scaled, y_train)))
print('Test score:{:.3f}'.format(logistic.score(X_test_scaled, y_test)))
print('Confustion matrix:\n{}'.format(confusion_matrix(y_true=y_test, y_pred = logistic.predict(X_test_scaled))))

# 2次元まで圧縮
pca = PCA(n_components=2)

x_train_pca = pca.fit_transform(X_train_scaled)
x_test_pca = pca.fit_transform(X_test_scaled)
print('cancer df shape:{}'.format(x_test_pca.shape))
logistic = LogisticRegressionCV(cv = 10, random_state = 0)
logistic.fit(x_train_pca, y_train)

# 検証
print('Train score:{:.3f}'.format(logistic.score(x_train_pca, y_train)))
print('Test score:{:.3f}'.format(logistic.score(x_test_pca, y_test)))
print('Confustion matrix:\n{}'.format(confusion_matrix(y_true=y_test, y_pred = logistic.predict(x_test_pca))))

32次元での結果
・Train score:0.988
・Test score:0.972
・Confustion matrix:[[89 1] [ 3 50]]

2次元に圧縮した結果
・Train score:0.965
・Test score:0.916
・Confustion matrix:[[83 7] [ 5 48]]

2次元に圧縮した割には判定できていると考えるのか、Testで6%落ちたのを致命的と考えるのか・・・

サポートベクタマシン-ハンズオン

線形分離可能なデータ

データの生成

import numpy as np
import matplotlib.pyplot as plt
def gen_data():
    x0 = np.random.normal(size=50).reshape(-1, 2) - 2.
    x1 = np.random.normal(size=50).reshape(-1, 2) + 2.
    X_train = np.concatenate([x0, x1])
    ys_train = np.concatenate([np.zeros(25), np.ones(25)]).astype(np.int)
    return X_train, ys_train

X_train, ys_train = gen_data()
plt.scatter(X_train[:, 0], X_train[:, 1], c=ys_train)
plt.show()

学習

t = np.where(ys_train == 1.0, 1.0, -1.0)

n_samples = len(X_train)
# 線形カーネル
K = X_train.dot(X_train.T)

eta1 = 0.01
eta2 = 0.001
n_iter = 500

H = np.outer(t, t) * K

a = np.ones(n_samples)
for _ in range(n_iter):
    grad = 1 - H.dot(a)
    a += eta1 * grad
    a -= eta2 * a.dot(t) * t
    a = np.where(a > 0, a, 0)

予測

index = a > 1e-6
support_vectors = X_train[index]
support_vector_t = t[index]
support_vector_a = a[index]

term2 = K[index][:, index].dot(support_vector_a * support_vector_t)
b = (support_vector_t - term2).mean()

xx0, xx1 = np.meshgrid(np.linspace(-5, 5, 100), np.linspace(-5, 5, 100))
xx = np.array([xx0, xx1]).reshape(2, -1).T

X_test = xx
y_project = np.ones(len(X_test)) * b
for i in range(len(X_test)):
    for a, sv_t, sv in zip(support_vector_a, support_vector_t, support_vectors):
        y_project[i] += a * sv_t * sv.dot(X_test[i])
y_pred = np.sign(y_project)

可視化

plt.scatter(X_train[:, 0], X_train[:, 1], c=ys_train)
# サポートベクトルを可視化
plt.scatter(support_vectors[:, 0], support_vectors[:, 1],
                    s=100, facecolors='none', edgecolors='k')
# マージンと決定境界を可視化
plt.contour(xx0, xx1, y_project.reshape(100, 100), colors='k',
                     levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])


# マージンと決定境界を可視化
plt.quiver(0, 0, 0.1, 0.35, width=0.01, scale=1, color='pink')
plt.show()

結果

入力データ 結果
Fig10.png Fig11.png

線形分離不可能なデータ

データの生成

factor = .2
n_samples = 50
linspace = np.linspace(0, 2 * np.pi, n_samples // 2 + 1)[:-1]
outer_circ_x = np.cos(linspace)
outer_circ_y = np.sin(linspace)
inner_circ_x = outer_circ_x * factor
inner_circ_y = outer_circ_y * factor

X = np.vstack((np.append(outer_circ_x, inner_circ_x),
               np.append(outer_circ_y, inner_circ_y))).T
y = np.hstack([np.zeros(n_samples // 2, dtype=np.intp),
               np.ones(n_samples // 2, dtype=np.intp)])
X += np.random.normal(scale=0.15, size=X.shape)
x_train = X
y_train = y
plt.scatter(x_train[:,0], x_train[:,1], c=y_train)
plt.show()

学習

def rbf(u, v):
        sigma = 0.8
        return np.exp(-0.5 * ((u - v)**2).sum() / sigma**2)
    
X_train = x_train
t = np.where(y_train == 1.0, 1.0, -1.0)

n_samples = len(X_train)
# RBFカーネル
K = np.zeros((n_samples, n_samples))
for i in range(n_samples):
    for j in range(n_samples):
        K[i, j] = rbf(X_train[i], X_train[j])

eta1 = 0.01
eta2 = 0.001
n_iter = 5000

H = np.outer(t, t) * K

a = np.ones(n_samples)
for _ in range(n_iter):
    grad = 1 - H.dot(a)
    a += eta1 * grad
    a -= eta2 * a.dot(t) * t
    a = np.where(a > 0, a, 0)

予測

index = a > 1e-6
support_vectors = X_train[index]
support_vector_t = t[index]
support_vector_a = a[index]

term2 = K[index][:, index].dot(support_vector_a * support_vector_t)
b = (support_vector_t - term2).mean()

xx0, xx1 = np.meshgrid(np.linspace(-1.5, 1.5, 100), np.linspace(-1.5, 1.5, 100))
xx = np.array([xx0, xx1]).reshape(2, -1).T

X_test = xx
y_project = np.ones(len(X_test)) * b
for i in range(len(X_test)):
    for a, sv_t, sv in zip(support_vector_a, support_vector_t, support_vectors):
        y_project[i] += a * sv_t * rbf(X_test[i], sv)
y_pred = np.sign(y_project)

可視化

# 訓練データを可視化
plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train)
# サポートベクトルを可視化
plt.scatter(support_vectors[:, 0], support_vectors[:, 1],
                    s=100, facecolors='none', edgecolors='k')
# 領域を可視化
plt.contourf(xx0, xx1, y_pred.reshape(100, 100), alpha=0.2, levels=np.linspace(0, 1, 3))
# マージンと決定境界を可視化
plt.contour(xx0, xx1, y_project.reshape(100, 100), colors='k',
                     levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])
plt.show()    
入力データ 結果
Fig12.png Fig13.png

ソフトマージン

重なり合うデータ

x0 = np.random.normal(size=50).reshape(-1, 2) - 1.
x1 = np.random.normal(size=50).reshape(-1, 2) + 1.
x_train = np.concatenate([x0, x1])
y_train = np.concatenate([np.zeros(25), np.ones(25)]).astype(np.int)

plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train)
plt.show()

学習

X_train = x_train
t = np.where(y_train == 1.0, 1.0, -1.0)

n_samples = len(X_train)
# 線形カーネル
K = X_train.dot(X_train.T)

C = 1
eta1 = 0.01
eta2 = 0.001
n_iter = 1000

H = np.outer(t, t) * K

a = np.ones(n_samples)
for _ in range(n_iter):
    grad = 1 - H.dot(a)
    a += eta1 * grad
    a -= eta2 * a.dot(t) * t
    a = np.clip(a, 0, C)

予測

index = a > 1e-8
support_vectors = X_train[index]
support_vector_t = t[index]
support_vector_a = a[index]

term2 = K[index][:, index].dot(support_vector_a * support_vector_t)
b = (support_vector_t - term2).mean()

xx0, xx1 = np.meshgrid(np.linspace(-4, 4, 100), np.linspace(-4, 4, 100))
xx = np.array([xx0, xx1]).reshape(2, -1).T

X_test = xx
y_project = np.ones(len(X_test)) * b
for i in range(len(X_test)):
    for a, sv_t, sv in zip(support_vector_a, support_vector_t, support_vectors):
        y_project[i] += a * sv_t * sv.dot(X_test[i])
y_pred = np.sign(y_project)

可視化

plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train)
# サポートベクトルを可視化
plt.scatter(support_vectors[:, 0], support_vectors[:, 1],
                    s=100, facecolors='none', edgecolors='k')
# 領域を可視化
plt.contourf(xx0, xx1, y_pred.reshape(100, 100), alpha=0.2, levels=np.linspace(0, 1, 3))
# マージンと決定境界を可視化
plt.contour(xx0, xx1, y_project.reshape(100, 100), colors='k',
                     levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])
plt.show()

結果

入力データ 結果
Fig14.png Fig15.png
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?