技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

教師あり学習アルゴリズム

pandas とか matplotlib とか色々弄っていく。
インプットはコレ

Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

Pythonではじめる機械学習 ―scikit-learnで学ぶ特徴量エンジニアリングと機械学習の基礎

全部は書かない。

先ずは必要なライブラリのインポート

Python で始める機械学習 という本の第二章先頭なのだけど、いきなり暗黙 import じみた事やってて初見殺しにも程があんだろ(汗

%matplotlib inline
from IPython.display import set_matplotlib_formats, display
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import mglearn

データの種類別散布図

で、改めてデータロード

X, y = mglearn.datasets.make_forge()
print(f"X.shape: {X.shape}")
X.shape: (26, 2)

そしてグラフ化
ちなみに、mglearn.discrete_scatter は、どうも pyplot の scartter を第3引数のデータごとに記号を変えて呼び出してくれるものらしい。

参考: テラテイルでの質問

mglearn.discrete_scatter(X[:, 0], X[:, 1], y)

plt.legend(["Class 0", "Class 1"], loc=4)
plt.xlabel("First feature")
plt.ylabel("Second feature")
Text(0, 0.5, 'Second feature')

[f:id:white-azalea:20190318232637p:plain]

それぞれのデータの中身を見ていく。
y はデータの種類を表して

y
array([1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0,
       0, 0, 1, 0])

X は、その座標を示してる。
こっちは x, y 座標のペアだ。

X

array([[ 9.96346605, 4.59676542], [11.0329545 , -0.16816717], [11.54155807, 5.21116083], [ 8.69289001, 1.54322016], [ 8.1062269 , 4.28695977], 中略 [11.563957 , 1.3389402 ]])

もっと他にも散布図

wave データセットというらしい。

他の散布図も作画してみる。
単純に x, y の配列だけを指定すると、データ分類のないシンプルな散布図ができる。

X, y = mglearn.datasets.make_wave(n_samples = 40)

plt.plot(X, y, 'o')
plt.ylim(-3, 3)
plt.xlabel('Feature')
plt.ylabel('Target')
Text(0, 0.5, 'Target')

[f:id:white-azalea:20190318232752p:plain]

y
array([-0.44822073,  0.33122576,  0.77932073,  0.03497884, -1.38773632,
       -2.47196233, -1.52730805,  1.49417157,  1.00032374,  0.22956153,
       -1.05979555,  0.7789638 ,  0.75418806, -1.51369739, -1.67303415,
       -0.90496988,  0.08448544, -0.52734666, -0.54114599, -0.3409073 ,
        0.21778193, -1.12469096,  0.37299129,  0.09756349, -0.98618122,
        0.96695428, -1.13455014,  0.69798591,  0.43655826, -0.95652133,
        0.03527881, -2.08581717, -0.47411033,  1.53708251,  0.86893293,
        1.87664889,  0.0945257 , -1.41502356,  0.25438895,  0.09398858])
X
array([[-0.75275929],
       [ 2.70428584],
       [ 1.39196365],
       [ 0.59195091],
       [-2.06388816],
       [-2.06403288],
       [-2.65149833],
       [ 2.19705687],
       [ 0.60669007],
       [ 1.24843547],
       /* 中略 */
       [ 1.10539816],
       [-0.35908504]])

乳癌データセット

恐ろしいなまえだなおい…マジか O'Reily 先生よ

from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
print(f"Cancer keys: {cancer.keys()}")
Cancer keys: dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])
cancer.data.shape
(569, 30)
[f'{n}: {v}' for n, v in zip(cancer.target_names, np.bincount(cancer.target))]
['malignant: 212', 'benign: 357']
cancer.feature_names
array(['mean radius', 'mean texture', 'mean perimeter', 'mean area',
       'mean smoothness', 'mean compactness', 'mean concavity',
       'mean concave points', 'mean symmetry', 'mean fractal dimension',
       'radius error', 'texture error', 'perimeter error', 'area error',
       'smoothness error', 'compactness error', 'concavity error',
       'concave points error', 'symmetry error',
       'fractal dimension error', 'worst radius', 'worst texture',
       'worst perimeter', 'worst area', 'worst smoothness',
       'worst compactness', 'worst concavity', 'worst concave points',
       'worst symmetry', 'worst fractal dimension'], dtype='<U23')

ボストンデータセット

1970 年代のボストン郊外の住宅価格の中央値、犯罪率、チャールズ川からの距離、高速道路への利便性。

from sklearn.datasets import load_boston

boston = load_boston()
boston.data.shape
(506, 13)

さらにこのデータをオライリー先生は拡張し、特徴量を 104 まで増やしたデータセットを作ったという。
13 の 2 組み合わせで、重複ありの 91 種類が追加されてるらしい。

X, y = mglearn.datasets.load_extended_boston()
X.shape
(506, 104)

K-NN アルゴリズム

これは不明なデータ(図では ☆)を、そこから「最も近いデータと多分同じ仲間なのだろう」とか、その捜索範囲で近い点 N 個の平均で、「多分○○の仲間なのだろう」という様な推測をするアルゴリズム
直近1個で決めるとこんな感じ。

尚、星の分類は色で示してる。

mglearn.plots.plot_knn_classification(n_neighbors=1)

f:id:white-azalea:20190318232934p:plain

これを直近3点で考えた時の分類。

mglearn.plots.plot_knn_classification(n_neighbors=3)

f:id:white-azalea:20190318233000p:plain

この様なアルゴリズムを scikit-learn でやってみる。
先ずはデータの読み込みと、学習/試験データへの分離。

from sklearn.model_selection import train_test_split

X, y = mglearn.datasets.make_forge()

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 0)

そして、K 近傍法アルゴリズムの設定と学習。

from sklearn.neighbors import KNeighborsClassifier

clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(X_train, y_train)
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=None, n_neighbors=3, p=2,
           weights='uniform')

さて、正答率は?

clf.score(X_test, y_test)
0.8571428571428571

K-近傍法の解析

学習した K-近傍法が、どの様な決定境界(ここを超えたら赤と認識する様な境界の事)を持つのかを見てみる。
ちなみに説明すると、subplots で 1 エリア 3 つのグラフ作成。

  • fig : Figure 図の意味。
  • axes : AxesSubplot(s) サブグラフリストの意味。

個人的にわからなくて調べた範囲だと、

  • plot_2d_separator
    これもやはり画面表示のヘルプらしい。二次元で境界線を作って作画してくれるようだ。
  • discrete_scatter
    第一引数 x 座標、第二引数 y 座標、第3引数 分類、ax 引数 作画対象の表を指定して、種類と色別に作画してくれるライブラリ。
fig, axes = plt.subplots(1, 3, figsize=(10, 3))

for n_neighbors, ax in zip([1, 3, 9], axes):
    clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X, y)
    
    mglearn.plots.plot_2d_separator(clf, X, fill=True, eps=0.5, ax=ax, alpha=0.4)
    mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax = ax)
    ax.set_title(f'{n_neighbors} neighbors')
    ax.set_xlabel('Feature 0')
    ax.set_ylabel('Feature 1')
    
axes[0].legend(loc=3)

f:id:white-azalea:20190318233042p:plain

じゃぁどの程度丸めるのがいいのかについて試してみる。
近傍の数をある程度の範囲で操作しつつ、トレーニングデータの一致率と、テストデータの一致率をそれぞれ確認する。

from sklearn.datasets import load_breast_cancer

# 乳癌データで試してみる。
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=66)

# 精度記録
training_accuaracy = []
test_accuaracy = []

# n_naighbors を 1 から 10 まで試す
neighbors_settings = range(1, 11)

for n_neighbors in neighbors_settings:

    # 学習機作って学習させて
    clf = KNeighborsClassifier(n_neighbors=n_neighbors)
    clf.fit(X_train, y_train)
    
    # 訓練セットの精度を記録する
    training_accuaracy.append(clf.score(X_train, y_train))
    
    # 汎化精度を記録
    test_accuaracy.append(clf.score(X_test, y_test))

# プロットしてみる
plt.plot(neighbors_settings, training_accuaracy, label='training_accuaracy')
plt.plot(neighbors_settings, test_accuaracy, label='test_accuaracy')
plt.legend()
plt.show()

f:id:white-azalea:20190318233135p:plain

K 近傍の数が増えるに連れて、個々のデータをみる様な事がなくなるので、およそ傾向的に判断する様になる。
一方で、学習データだけでみると、バースト値に惑わされなくなる分、精度が下がっていく傾向が出る。

でもじゃぁどの位の値がベストなのかは、正直このグラフを見てみるまでわからない気がする。

数字をあげすぎても未知だったデータに対しての正答率が下がるので、上げ過ぎもよくないようだ。

K-近傍回帰

K-近傍法で、回帰を行う変種を使ってみる。

mglearn.plots.plot_knn_regression(n_neighbors=1)

f:id:white-azalea:20190318233200p:plain

mglearn.plots.plot_knn_regression(n_neighbors=3)

f:id:white-azalea:20190318233219p:plain

図で見て理解したわ、これ K 平均法によく似てる。

from sklearn.neighbors import KNeighborsRegressor
X, y = mglearn.datasets.make_wave(n_samples = 40)

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

reg = KNeighborsRegressor(n_neighbors=3)
reg.fit(X_train, y_train)
KNeighborsRegressor(algorithm='auto', leaf_size=30, metric='minkowski',
          metric_params=None, n_jobs=None, n_neighbors=3, p=2,
          weights='uniform')

じゃーこの回帰で処理するとどれくらいの数字が出るのか?

reg.score(X_test, y_test)
0.8344172446249604