【ラビットチャレンジ】【機械学習】アルゴリズム

「ラビットチャレンジ」 提出レポート
#１．k近傍法(k-NN)
■　分類問題のための機械学習手法である。
　●　最近傍のデータを $k$ 個取ってきて、それらがもっとも多く所属するクラスに識別する。
■　$k$ を変化させると結果も変わる。$k=1 $ の場合は最近傍法という。
■　$k$ を大きくすると決定境界は滑らかになる。
#２．k平均法(k-means)
###【概要】
■　教師なし学習
■　クラスタリング手法（特徴の似ているもの同士をグループ化）
■　与えられたデータを $k$ 個のクラスタに分類する
###【アルゴリズム】
■　各クラスタ中心の初期値を設定する
■　各データ点に対して、各クラスタ中心との距離を計算し、最も距離が近いクラスタを割り当てる
■　各クラスタの平均ベクトル（中心）を計算する
■　収束するまで2, 3の処理を繰り返す
■　中心の初期値を変えるとクラスタリング結果も変わりうる
■　$k$ の値を変えるとクラスタリング結果も変わる
#３．ハンズオン
##k近傍法(k-NN)
###【実装演習結果】
　●　設定：人口データを分類
　●　課題：人口データと分類結果をプロットしてください

■　**必要モジュールとデータのインポート**

```python
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
```
■　**訓練データ生成**

```python
def gen_data():
    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)
    return x_train, y_train

X_train, ys_train = gen_data()
plt.scatter(X_train[:, 0], X_train[:, 1], c=ys_train)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/9162a604-c748-9c4a-80a9-c163e8fb7ae1.png)
■　**学習** 
陽に訓練ステップはない
■　**予測** 
予測するデータ点との、距離が最も近い $k$  個の、訓練データのラベルの最頻値を割り当てる

```python
def distance(x1, x2):
    return np.sum((x1 - x2)**2, axis=1)

def knc_predict(n_neighbors, x_train, y_train, X_test):
    y_pred = np.empty(len(X_test), dtype=y_train.dtype)
    for i, x in enumerate(X_test):
        distances = distance(x, X_train)
        nearest_index = distances.argsort()[:n_neighbors]
        mode, _ = stats.mode(y_train[nearest_index])
        y_pred[i] = mode
    return y_pred

def plt_resut(x_train, y_train, y_pred):
    xx0, xx1 = np.meshgrid(np.linspace(-5, 5, 100), np.linspace(-5, 5, 100))
    xx = np.array([xx0, xx1]).reshape(2, -1).T
    plt.scatter(x_train[:, 0], x_train[:, 1], c=y_train)
    plt.contourf(xx0, xx1, y_pred.reshape(100, 100).astype(dtype=np.float), alpha=0.2, levels=np.linspace(0, 1, 3))
```
```python
n_neighbors = 3
xx0, xx1 = np.meshgrid(np.linspace(-5, 5, 100), np.linspace(-5, 5, 100))
X_test = np.array([xx0, xx1]).reshape(2, -1).T

y_pred = knc_predict(n_neighbors, X_train, ys_train, X_test)
plt_resut(X_train, ys_train, y_pred)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/39806b31-99ac-4047-159f-dd8f8a81e0f2.png)
■　**numpy実装**

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

from sklearn.neighbors import KNeighborsClassifier
knc = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X_train, ys_train)
plt_resut(X_train, ys_train, knc.predict(xx))
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/faef652c-8b2b-e31d-11e7-00b7f078b692.png)

###【考察】
■　k近傍法を使用ことで、データの分類ができた。
■　上のパラメータ（n_neighbors）の値を大きく設定して、決定境界は滑らかになるかどうかを確認してみた。
●　n_neighbors＝20にすると、以下の結果のように、決定境界は滑らかになった。

```python
n_neighbors = 20

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

y_pred = knc_predict(n_neighbors, X_train, ys_train, X_test)
plt_resut(X_train, ys_train, y_pred)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/e1b0a89d-bf05-96df-1ba6-b8c058ff0424.png)

##k平均法(k-means)
###【実装演習結果】
■　**必要モジュールのインポート**

```python
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
```
■　**データ生成**

```python
def gen_data():
    x1 = np.random.normal(size=(100, 2)) + np.array([-5, -5])
    x2 = np.random.normal(size=(100, 2)) + np.array([5, -5])
    x3 = np.random.normal(size=(100, 2)) + np.array([0, 5])
    return np.vstack((x1, x2, x3))

#データ作成
X_train = gen_data()
#データ描画
plt.scatter(X_train[:, 0], X_train[:, 1])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/5df986ea-a42a-f9c4-4528-e773e5295874.png)
■　**学習** 
k-meansアルゴリズムは以下のとおりである
1) 各クラスタ中心の初期値を設定する
2) 各データ点に対して、各クラスタ中心との距離を計算し、最も距離が近いクラスタを割り当てる
3) 各クラスタの平均ベクトル（中心）を計算する
4) 収束するまで2, 3の処理を繰り返す

```python
def distance(x1, x2):
    return np.sum((x1 - x2)**2, axis=1)

n_clusters = 3
iter_max = 100

# 各クラスタ中心をランダムに初期化
centers = X_train[np.random.choice(len(X_train), n_clusters, replace=False)]

for _ in range(iter_max):
    prev_centers = np.copy(centers)
    D = np.zeros((len(X_train), n_clusters))
    # 各データ点に対して、各クラスタ中心との距離を計算
    for i, x in enumerate(X_train):
        D[i] = distance(x, centers)
    # 各データ点に、最も距離が近いクラスタを割り当
    cluster_index = np.argmin(D, axis=1)
    # 各クラスタの中心を計算
    for k in range(n_clusters):
        index_k = cluster_index == k
        centers[k] = np.mean(X_train[index_k], axis=0)
    # 収束判定
    if np.allclose(prev_centers, centers):
        break
```
■　**クラスタリング結果**

```python
def plt_result(X_train, centers, xx):
    #　データを可視化
    plt.scatter(X_train[:, 0], X_train[:, 1], c=y_pred, cmap='spring')
    # 中心を可視化
    plt.scatter(centers[:, 0], centers[:, 1], s=200, marker='X', lw=2, c='black', edgecolor="white")
    # 領域の可視化
    pred = np.empty(len(xx), dtype=int)
    for i, x in enumerate(xx):
        d = distance(x, centers)
        pred[i] = np.argmin(d)
    plt.contourf(xx0, xx1, pred.reshape(100, 100), alpha=0.2, cmap='spring')

y_pred = np.empty(len(X_train), dtype=int)
for i, x in enumerate(X_train):
    d = distance(x, centers)
    y_pred[i] = np.argmin(d)

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

plt_result(X_train, centers, xx)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/940c425d-1a7e-b57d-56eb-b18f04e23aa7.png)
■　**numpy実装**

```python
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, random_state=0).fit(X_train)

print("labels: {}".format(kmeans.labels_))
print("cluster_centers: {}".format(kmeans.cluster_centers_))
kmeans.cluster_centers_
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552833/cea3ee2b-f27c-ca85-2883-011dc36828e7.png)

###【考察】
■　k近傍法(k-NN)、k平均法(k-means)のアルゴリズムを理解しやすい。
■　k-means手法では、結果が初期値に大きく依存するという問題点がある。
■　最初にクラスタの数を決めなければならない。

##【機械学習】レポート一覧
[【ラビットチャレンジ】【機械学習】線形回帰モデル](https://qiita.com/HienDT27/items/0cbed5d1771b13d0311c)
[【ラビットチャレンジ】【機械学習】非線形回帰モデル](https://qiita.com/HienDT27/items/0f785e4835a85a8cd4ad)
[【ラビットチャレンジ】【機械学習】ロジスティク回帰モデル](https://qiita.com/HienDT27/items/cd067099c970a9786a47)
[【ラビットチャレンジ】【機械学習】主成分分析](https://qiita.com/HienDT27/items/bd53678695d33a6f8ee5)
[【ラビットチャレンジ】【機械学習】サポートベクターマシン](https://qiita.com/HienDT27/items/aa7317a8394212940068)