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?

Python初心者の備忘録 #21 ~機械学習入門編07~

Posted at

はじめに

今回私は最近はやりのchatGPTに興味を持ち、深層学習について学んでみたいと思い立ちました!
深層学習といえばPythonということなので、最終的にはPythonを使って深層学習ができるとこまでコツコツと学習していくことにしました。
ただ、勉強するだけではなく少しでもアウトプットをしようということで、備忘録として学習した内容をまとめていこうと思います。
この記事が少しでも誰かの糧になることを願っております!
※投稿主の環境はWindowsなのでMacの方は多少違う部分が出てくると思いますが、ご了承ください。
最初の記事:Python初心者の備忘録 #01
前の記事:Python初心者の備忘録 #20 ~機械学習入門編06~
次の記事:まだ

今回はクラスタリング決定木SVMについてまとめております。

■学習に使用している資料

Udemy:【後編】米国データサイエンティストがやさしく教える機械学習超入門【Pythonで実践】

■クラスタリング(Clustering)

▶クラスタリングとは

  • 教師データを使わない分類タスクの一種
    データをカテゴリーやクラス、ラベルと呼ばれる「種類」に分別・グループ化していく

分類/識別(classification)との違い
クラスタリングは教師なし学習

教師あり/なし学習のおさらい

教師あり学習(Supervised learning)
  • 正解の情報(ラベルや値)から損失を計算し、損失が最小となるようにモデルを構築
    ※回帰や分類タスクは教師あり学習
  • ◎ 正解があるのでモデルの結果に対して解釈しやすい
  • ✕ 正解データを集める必要がある

image.png

教師なし学習(Unsuperviced learning)
  • 類似しているデータをグループ(クラスタ)にしてデータを分類
    ※クラスタリングは教師なし学習
  • ✕ 正解データがないのでやり方によって結果が色々と異なり解釈が難しい
  • ◎ 正解データを集める必要がないので簡単に行える

explaine_clustering_image.png

クラスタリングの実用例

  • Fake Newsやスパムメールなどの判定:その時に正解がわからないことが多い
  • 顧客のセグメンテーション(マーケティング):対象によって正解が異なる
  • 画像処理:似た画像でも光の加減でRGB値が異なるので正解を決めにくい

▶k-means

  • 最も基本的なクラスタリングアルゴリズム
  • データをk個のクラスタに分類する
    → 各クラスタ内の分散の合計が全体で最小となるようにする

image.png

k-meansの損失関数

  • 全クラスタ内の各データ同士の差の平方和(クラスタ内分散)の合計を損失関数とする
    ※あるアルゴリズムに従って局所解を見つける
    クラスタ内分散:$min(\sum_{k=1}^K\sum_{i,i'\in C_{k}}(x_i-x_{i'})^2)$

clustering_culcuration.png

k-meansのアルゴリズム

  1. ランダムにそれぞれのデータに対して1~Kのクラスタに振り分ける
  2. クラスタが変更しなくなるまで以下を繰り返す
    1. 各クラスタの中心を求める
    2. 最も近いクラスタの中心をそのデータのクラスタとする

image.png

このアルゴリズムで行きつく答えは最適解(Gloval Optima)にならず、極小解(Local Optima)となることがあることに注意する。
→ そのためk-meansを複数回行い、解が最小となるものを選択するのが一般的

▶K(クラスタ数)の決め方

  • (当然)データ数よりも少ない必要がある
  • 明確な正解はなく、ドメイン知識やデータの背景から仮説を立てる必要がある
    → いろいろなKを試して考察するのが一番

image.png
とは言いつつも方法がないわけではなく、方法の一つにElbow methodがある。

Elbow method

  • Kを増やしていき、損失が急に下がったところのKを採用する方法
    ※必ずしもElbowがあるとは限らない
    image.png

Pythonでk-means

  • sklearn.cluster.KMeansライブラリを使用する
    1. KMeans(n_clusters)でインスタンス生成(n_cluster:クラスタ数の指定)
    2. .fit(X)で学習 → クラスタリング実行
      • .predict(X)で各データのクラスタリングの結果を参照
      • .score(X)で損失を計算
k-means
# データ準備
import seaborn as sns
df = sns.load_dataset('iris')
X = df.drop(columns=['species'])

# 標準化
from sklearn.preprocessing import StandardScaler
X_scaled = StandardScaler().fit_transform(X)

# k-means
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, random_state=0)
labels = kmeans.fit_predict(X_scaled) # .fit(X)と.predict(X)を同時に行う
result
# ilisデータのクラスタリング結果が出ている
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2,
       0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2,
       2, 2, 2, 0, 0, 2, 2, 2, 2, 0, 2, 0, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2,
       2, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 0], dtype=int32)

k-meansの描画

## データの分布を描画
import pandas as pd
result_df = pd.concat([X, pd.DataFrame(labels, columns=['kmean_result'])], axis=1)
sns.pairplot(result_df, hue='kmean_result')

image.png

# 教師付きのデータ分布
sns.pairplot(df, hue='species')

image.png

教師なし学習であるクラスタリングの描画と教師あり学習の分類の描画では大体あっているが多少の違いがあることがわかる。
→ 教師なし学習のクラスタリングでは正解を出すことは難しいが、ある程度の判断材料には使用できる。

k-meansの損失の推移を描画

import matplotlib.pyplot as plt
# Kが1~9の時の損失関数を計算
losses = []
for K in range(1, 10):
    kmeans = KMeans(n_clusters=K, random_state=0).fit(X_scaled)
    losses.append(-kmeans.score(X_scaled))

# Elbow methodを描画
plt.plot(range(1, 10), losses)
plt.xlabel('K')
plt.ylabel('loss')

image.png
Elbow methodを見る限り、Kは2か3がよさそうと分かる

▶k-meansの注意点

  • 特徴量の数が多い(高次元空間)場合は2組のデータ間の距離に差がなくなってくるので、うまくクラスタリングできなくなる:次元の呪い(curse of dimensionality)
    特徴量選択やPCAで次元削減する

image.png

  • 質的変数との相性が悪い
    • ダミー変数化して距離を計算しても距離の意味を持たない
      $\sqrt{(0-1)^2+(1-1)^2+(1-0)^2}$:0か1でしか計算できない
    • 高次元化し、やはりデータ間の距離に差がなくなっていく
      量的変数のみでk-meansをしたり、k-modesなどの別のアルゴリズムを使用する

▶階層クラスタリング(Hierarchical Clustering)

  • k-meansと双璧を成す有名なクラスタリング手法
  • 事前にクラスタ数(K)を指定する必要がないのことが特徴で、dendrogram(樹状図)を作り"階層的に"クラスタリングする

image.png

dendrogramとは

  • 階層クラスタリングにおいてクラスタリングされていった過程を表したもの
    clustering_culcuration.png

階層クラスタリングのアルゴリズムの流れ

※データは事前に標準化しておく

  1. (初期設定)各データを各クラスタとする
  2. 距離が最も近いクラスタ同士を融合し、1つのクラスタにする
  3. 2.を繰り返す
  4. 最終的にクラスが1つになり終了

clustering_culcuration.png

▶クラスタ間の距離の測り方

single

  • クラスタ間で最も近いデータの距離
    ※たまたま1つでも近いデータがあれば融合してしまうのでバランスが悪くなりがち

image.png

complete

  • クラスタ間で最も遠いデータの距離

image.png

average

  • クラスタ間のすべての2組のデータの距離の平均

image.png

centroid

  • 各クラスタの中心間の距離

image.png

inversionが起こる可能性あり
image.png

ward(ウォード法)

  • 全データの中心から各データの距離の二乗和(分散)から、それぞれのクラスタの中心とそのクラスタのデータの距離の二乗和を引いた値
  • 計算量は多いが分類の感度が良いのでよく使われる

image.png

類似度(距離)の定義

  • ユークリッド距離
    ※特に理由がなければこれを使用する

image.png

  • マンハッタン距離
    ※直線距離ではなく、直角に迂回するように距離を算出する

clustering_culcuration.png

相関を使って類似度を測る

  • 距離でうまくクラスタリングできないケースでは相関を使うことでうまく出来ることがある

image.png

▶dengrogramの使い方と注意点

  • 縦軸の任意の箇所で切ることで、好きなクラスタ数でクラスタリングができる

clustering_culcuration.png

注意点

  • ネストできない様なデータに対してもネスト型の階層を作ってしまう
    → Kの値によって分類の軸を分けることができない

image.png

▶Pythonで階層クラスタリング

階層クラスタリング

  • scipy.cluster.hierarchy.linkageライブラリを使用
  • linkage(X, method)でクラスタリングを実施
    • methodには'single', 'average', 'complete', 'centroid', 'ward'等を指定
  • dendrogramを構成する情報をNumpy Arrayで返す
    • [クラスタ1のindex, クラスタ2のindex, 距離, データの数]
      • index < データ数:学習データのインデックス(クラスタ = データ)
      • index >= データ数:linkageの戻り値のindex(結合されたクラスタに割り振られたindex)

clustering_culcuration.png

階層クラスタリング
from scipy.cluster.hierarchy import linkage, dendrogram
Z = linkage(X_scaled, method='ward')
# [クラスタ1のidx, クラスタ2のidx, 距離, データ数]のリスト
# idxは,idx<len(X)ならX[idx] idx>=len(X)ならZ[idx-len(X)]でクラスタを取得
Z[:10]
result
# n回目のクラスタリングで使用したデータの情報[クラスタ1のidx, クラスタ2のidx, 距離, データ数]のリスト
array([[1.01000000e+02, 1.42000000e+02, 0.00000000e+00, 2.00000000e+00],
       [7.00000000e+00, 3.90000000e+01, 1.21167870e-01, 2.00000000e+00],
       [1.00000000e+01, 4.80000000e+01, 1.21167870e-01, 2.00000000e+00],
       [9.00000000e+00, 3.40000000e+01, 1.31632184e-01, 2.00000000e+00],
       [0.00000000e+00, 1.70000000e+01, 1.31632184e-01, 2.00000000e+00],
       [1.28000000e+02, 1.32000000e+02, 1.31632184e-01, 2.00000000e+00],
       [1.27000000e+02, 1.38000000e+02, 1.33836265e-01, 2.00000000e+00],
       [2.00000000e+00, 4.70000000e+01, 1.33836265e-01, 2.00000000e+00],
       [8.00000000e+01, 8.10000000e+01, 1.43378956e-01, 2.00000000e+00],
       [1.90000000e+01, 4.60000000e+01, 1.43378956e-01, 2.00000000e+00]])

dendrogram

  • scipy.cluster.hierarchy.dendrogramライブラリを使用
  • dendrogram(Z)で描画
    • Zにはlinkageの戻り値を入れる
  • trancate_mode引数およびp引数で任意の高さでdendrogramを切ることができる
    • trancate_mode='lastp', p=K:指定したK個のクラスタになるように切る
    • trancate_mode='lastp', p=段数:p段になるように切る
dendrogram
d = dendrogram(Z, truncate_mode='level', p=2)

image.png

▶実際にクラスタリングしてみる

各データのラベル付け

  • scipy.cluster.hierarchy.fclusterライブラリを使用
    • Z:linkage関数の戻り値
    • criterion引数:どの段階のクラス手分けを使うかを指定
      • 'maxclust't引数に指定したクラスタ数でラベル付けを行う
    • t引数:criterion引数によって異なる値を指定する
クラスタの分布描画
from scipy.cluster.hierarchy import fcluster

# ラベル付け
clusters = fcluster(Z, criterion='maxclust', t=3)


hc_result_df = pd.concat([X, pd.DataFrame({'cluster': clusters})], axis=1)
sns.pairplot(hc_result_df, hue='cluster')

image.png

実際の分布
sns.pairplot(df, hue='species')

image.png

■決定木

▶決定木とは

  • 回帰にも分類にも使用できるアルゴリズムで、人間の意思決定のロジックに近いので非常に解釈しやすい
  • 単体での制度は低く、複数の決定木を組み合わせることで非常に高い精度モデルを構築できる

image.png
左がtrue、右がfalse、yは高さ

決定木の部位の名称
image.png

▶決定木のアルゴリズム概要

  • データを2つの領域に分割していく
    回帰の場合:領域の学習データの平均値を予測値をする
    分類の場合:多数決

clustering_culcuration.png

▶領域の分割の仕方

回帰

  • 分割後の2つの領域の残差(偏差)の平方和の合計が最小になるように二分していく

image.png

分類

  • ジニ不純度(gini impurity) を使用
    • どれだけ綺麗に分けられるかを表す指標
      ⇒ どれだけ「不純なもの」が含まれるか
      $G=\sum_{k=1}^Kp(k)(1-p(k))$($K$:クラス数、$p(k)$:その領域でのクラスkの割合)
  • 分割後の2つの領域のジニ不純度の合計が最小になるように二分していく

image.png

理想はすべての領域における偏差の平方和の合計が最小になることだが、それだと計算量が高くなるので分割毎に最小になるようにする

そのため、最終的にすべての領域の平方和の合計が最小になるとは限らない...
⇒ 途中の分割が後々悪い分割になる可能性もある。(最適解ではなく、極小解を求めている)

▶決定木の過学習

  • 分割を進めていくとモデルが複雑になり、過学習で汎化性能が下がる
    ⇒ 精度の低下、解釈性の低下、学習時間の増大が発生する

image.png

決定木の分割を途中で終了する

  • 主に使用されるのは以下の2パターン
    • 深さを指定
    • 葉の最小データ数を指定

image.png

決定木の剪定(pruning)

  • 葉の数だけペナルティを与える(cost complexity pruning)

clustering_culcuration.png
image.png

最も小さい$\alpha$を持つ枝から選定していくとは?
$\alpha$が小さくても分割前と分割後の損失の差がほとんどないということは、分割しなくても結果に影響しないということになる。
⇒ つまり、分割の必要性が低い

▶Pythonで決定木

回帰

  • sklean.tree.DecisionTreeRegressorライブラリを使用
    • max_depth:木の深さを指定
    • min_samples_split:最低限分割に必要なデータ数を指定
    • ccp_alpha:cost complexity pruningの$\alpha$の値を指定
  • 使い方は他のsklearnのモデルと同じで、パラメータをしていないと最後まで学習して過学習を起こすので注意

分類

  • sklean.tree.DecisionTreeClassifierライブラリを使用
    ※使い方は回帰と同じ
回帰
import seaborn as sns
import pandas as pd
from sklearn.model_selection import train_test_split

# データ準備
df = sns.load_dataset('tips')
df = pd.get_dummies(df, drop_first=True)
y_col = 'tip'
X = df.drop(columns=[y_col])
y = df[y_col]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# 決定木モデル(回帰)
from sklearn import tree
model = tree.DecisionTreeRegressor(max_depth=4)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)

# MSE
from sklearn.metrics import mean_squared_error
mean_squared_error(y_test, y_pred) # -> 1.1060246260428703

# R^2(R-squared)
model.score(X_test, y_test) # -> 0.3590618660303134

▶決定木の可視化

描画

  • sklearn.tree.plot_treeライブラリを使用
    • decision_tree:sklearnのtreeモデルを引数にする
    • fontsize:フォントサイズを指定
    • feature_name:特徴量の名前をリストで渡す(model.feature_names_in_が便利)
  • 図の内容が戻り値で返ってくる

image.png

描画
# figureサイズの調整
import matplotlib.pyplot as plt
plt.figure(figsize=(40, 20))

# 決定木の描画
_ = tree.plot_tree(model, fontsize=10, feature_names=model.feature_names_in_)

image.png

テキスト

  • sklearn.tree.export_textライブラリを使用
    ※使い方はplot_treeと同じ
  • print()関数に渡すことできれいに表示される

image.png

テキスト
print(tree.export_text(model, feature_names=list(model.feature_names_in_)))

image.png

▶決定木の特徴量の重要性

  • 予測に重要な特徴量ほど決定木の上部で分岐される

image.png

Pythonで重量度の可視化

  • .feature_importances_属性でモデル内の特徴量の重要度を取得できる
    ⇒ 分岐の際にどれだけ不純度を下げることができたかで計算する
特徴量の重要度の描画
# 各特徴量の重要度
model.feature_importances_ # -> array([0.87823592, 0.07825569, 0., 0.03169922, 0., 0.01180916, 0., 0.])

# 描画
plt.barh(model.feature_names_in_, model.feature_importances_)

image.png

▶Minimal cost complexity pruning(剪定)

  • .cost_complecity_pruning_path(X, y)で、$\alpha$と不純度をリストで取得できる
  • それぞれの$\alpha$でのモデルの精度を計測し、最良の$\alpha$を使用する

image.png

剪定
# model作成
model = tree.DecisionTreeRegressor(random_state=0)

# 決定木を剪定する閾値となるαと不純度のリスト
path = model.cost_complexity_pruning_path(X_train, y_train)
eff_alphas = path.ccp_alphas

# 各αでのモデルを構築
models = []
for eff_alpha in eff_alphas:
    model = tree.DecisionTreeRegressor(random_state=0, ccp_alpha=eff_alpha)
    model.fit(X_train, y_train)
    models.append(model)

# それぞれのモデルの精度指標を記録(上記のfor文の中で実行した方が効率がいいが,ここでは別ループにて実行する)
from sklearn.metrics import mean_squared_error
train_scores = [mean_squared_error(y_train, model.predict(X_train)) for model in models]
test_scores = [mean_squared_error(y_test, model.predict(X_test)) for model in models]

# 各αで剪定したときのモデルの精度の推移を描画
plt.plot(eff_alphas, train_scores, marker='o', label='train', drawstyle='steps-post')
plt.plot(eff_alphas, test_scores, marker='o', label='test', drawstyle='steps-post')
plt.legend()
plt.xlabel('alpha')
plt.ylabel('MSE')

image.png
大体$\alpha$が1の時のモデルがちょうどよさそうというのが見てとれる

最後まで剪定したモデルを見てみる

print(tree.export_text(models[-1], feature_names=list(models[-1].feature_names_in_)))

image.png
1つしかない ⇒ モデルが極限にシンプルになっている

予測
models[-1].predict(X_test)
result
# 全て2.96...と予測される
array([2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412, 2.96429412,
       2.96429412, 2.96429412, 2.96429412, 2.96429412])

■SVM(Support Vector Machine)

▶SVMとは

  • 分類と回帰のどちらにも使用可能で、単体のモデルとしては精度が高いことで有名
    ※深層学習を除いて...
  • 決定境界を引くことで分類を行う

image.png

  • この決定境界があまりにギリギリだと未知のデータを誤分類してしまう可能性がある

image.png

  • 決定境界線はある程度の余裕(マージン)を取って引いた方がいい

image.png

結論

  • 直近のデータからある程度余裕を持った方が未知のデータにも対応できる
  • あるデータがサポートとなり,そこからの距離(マージン)が最大化するように決定境界をひく
  • 距離を使うので事前にSVMでは標準化することが望ましい

image.png

▶ソフトマージンとハードマージン

ハードマージン

  • 誤分類を許容しないので、外れ値があると大きく結果が変わってしまう
    ⇒ high variance、過学習、汎化性能が低いモデルになる

image.png

ソフトマージン

  • 誤分類を許容するので、外れ値があった場合でも大きく結果は変わらない
    ⇒ モデルのロバスト性が高くなる
  • マージンの中にデータが入ることも許容する(ハードマージンでは許容しない)
    ※境界の直近のデータがサポートベクターになるとは限らない

image.png

▶SVMの損失関数

  • マージンを最大化しつつ誤分類を減らすような関数
    $min(\frac{1}{M}+C\sum_{i=1}^m\xi_i)$ ⇒ パラメータCにより誤分類の許容を調整する

超平面

  • n次元空間内の平坦なn-1次元の集合
    ⇒ 2次元空間の超平面は線(1次元)、3次元空間の超平面は平面(2次元)
  • 線形分類器の決定境界は超平面になる
    つまり、マージンは超平面からの距離ということになる

image.png

ヒンジ損失(hinge loss)

  • 交差エントロピー(log loss)を近似した損失で、近似により計算量が削減できる
  • 1>や-1<で損失するようにすることで、マージンを考慮した損失となる

image.png

上図において、$\theta^Tx$が0の時にp(x)=0.5になり、0より大きいか小さいかで正解/不正解の識別は可能のように見えるが、それぞれ1や-1までいかなければ十分なマージンではないということを表している。

ハードマージンにおける制約

  • 誤分類が許されないので、以下のような制約で最適化問題を解くこととなる

image.png

ソフトマージンにおける制約

  • 誤分類を許容するので、制約は以下のように緩める

image.png

▶非線形の分類

  • SVMを非線形分離可能のアルゴリズムとする
  • 特徴量空間を非線形変換することで非線形分離を実現する

image.png

カーネルトリック(kernel trick)

  • 特徴量を写像した際に膨大となる各データ間の内積の計算を解決する方法
    カーネル関数:$K(x_i, x_j)=\phi(x_i)^T\phi(x_j)$
様々なカーネル関数
  • 多項式カーネル
    $K(x_i, x_j)=(x_i^Tx_j+c)^d$
  • ガウスカーネル
    $K(x_i, x_j)=exp(-\frac{||x_i-x_j||^2}{2\sigma^2})$
  • シグモイドカーネル
    $K(x_i, x_j)=\frac{1}{1+exp(-\gamma x_i^Tx_j)}$

▶PythonでSVM

  • sklearn.svm.SVCを使用する
    • C:エラーの正則化項の係数(誤分類の許容値と考えればいい)
    • kernel:使用するカーネル
      • linear,poly,rdf,sigmoidなど
    • degree:'poly'のd(デフォルトだと3)
    • gamma:'poly'、'rdf'、'sigmoid'の係数$\gamma$
      • 'scale':$\frac{1}{n×Var(X)}$(デフォルト)
      • 'auto':$\frac{1}{n}$
    • .support_vectors_でサポートベクトルのリストを取得
  • 回帰はsklearn.svm.SVR
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# データ準備
df = sns.load_dataset('iris')
y_col = 'species'
X = df.drop(columns=[y_col])
y = df[y_col]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# 標準化
scaler = StandardScaler().fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

# PCA
pca = PCA(n_components=2)
X_train_pc = pca.fit_transform(X_train)
X_test_pc = pca.transform(X_test)

# 学習(SVM)
from sklearn.svm import SVC
model = SVC(kernel='poly', C=100)
model.fit(X_train_pc, y_train)

# 予測
y_pred = model.predict(X_test_pc)

# 評価
from sklearn.metrics import accuracy_score
accuracy_score(y_test, y_pred) # -> 0.9333333333333333

# サポートベクトルのリスト取得
# model.support_vectors_

▶決定境界とサポートベクトルの可視化

  • sklearn.inspectopn.DecisionBoundaryDisplayを使用
    ※version 1.1から使用可能(python>3.8)
    • .from_estimator(model, X)で描画
from sklearn.inspection import DecisionBoundaryDisplay
import matplotlib.pyplot as plt
import numpy as np

# 決定境界描画
DecisionBoundaryDisplay.from_estimator(model, 
                                       X_train_pc,
                                       plot_method='contour',
                                       cmap=plt.cm.Paired,
                                       xlabel='first principal component',
                                       ylabel='second principal component')

# (PCA後の)学習データ描画
for class_, color in zip(model.classes_, 'bry'):
    idx = np.where(y_train == class_)
    plt.scatter(X_train_pc[idx, 0],
                X_train_pc[idx, 1],
                c=color,
                label=class_,
                edgecolor='black',
                s=20)

image.png

# サポートベクトル描画
plt.scatter(model.support_vectors_[:, 0],
            model.support_vectors_[:, 1],
            s=100,
            facecolor='none',
            linewidth=1,
            edgecolor='black')
plt.legend()

image.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?