この記事は個人的なお勉強用のメモです。
講義
k近傍法(kNN)
- 教師あり学習
- 分類を予測
- 予測対象のデータに最も近い k個のデータを取ってきて、それらのデータが最も多く所属するクラスを予測値とする、という単純なアルゴリズム。(要するに、多数決でクラスを決めるだけ)
kについて
- kの値によって分類の結果が変わる場合がある。
- kは事前に決めておく。(ハイパーパラメータ)
- kを大きくすると決定境界は滑らかになる。
k-平均法(k-means)
- 教師なし学習
- クラスタリングする(クラス分けする)
処理順序
- 分類する個数を決める。
- クラスタの中心の初期値をランダムに決める。
- 各データに対して、どれが最も近いクラスタの中心か求める。
- 各クラスタの平均ベクトル(中心)を計算する。
- 3と4を繰り返す。
クラスタの中心を変化させていって、変化が落ち着いたところが
クラスタリング終了といったところか。
特徴
- 中心の初期値が近いと、うまくクラスタリングできない。
k-means++という手法を使うと、初期値がうまくばらける。 - kの値を変えるとクラスタリング結果も変わる。
人間の目で見てkの値を判断する必要性がある。
修了テスト~練習問題~(kNN)
kNNの問題が無い。
修了テスト~練習問題~(k-means)
問題22(k-means)
内側の1つ目のforループ
データごとに最も近いクラスタの中心を求める処理。
for centroid in centroids:
for i, x in enumerate(data):
indexes[i] = np.argmin(np.sum((x - centroid) ** 2, axis=1))
説明
x:既存の1つのデータ
centroid:クラスタの中心の1つのデータ
x - centroid:成分ごとの差を求める。
(...) **2:成分の差ごとに二乗する。
np.sum(..., axis=1):異なる成分の差を足す。足すのは右方向。
np.argmin:最小値を持つインデックスを返す。
問題23(k-means)
内側の2つ目のforループ
クラスタの中心を再計算する。
再計算とは、データの平均値を求める。
for i in range(k):
centroisd[i] = data[indexes==i].mean(axis=0)
説明
k:クラスタの個数(4個)
i:クラスタの番号(みたいなもの、0~3)
centroids:クラスタの中心が複数
data[indexes==i]:クラスタの番号iと一致するdataを抽出する。
data[...].mean:該当するデータの平均値を計算する。
問題25(k-means)
k-meansの欠点は、初期値が近いとうまくクラスタリングできないこと。
k-means++によって、この欠点が改良された。
問題26(k-means++)
k-means++で初期のクラスタの中心(セントロイド)を決めるアルゴリズム
probabilities = np.repeat(1/n, n)
centroids = np.zeros((k, 2))
distances = np.zeros((n, k))
for in in range(k):
centroids[i] = data[np.random.choice(np.arange(n), p=probabirities, size=(1))]
distances[:, i] = np.sum((data - centroids[i]) ** 2, axis=1)
probabilities = np.sum(distance, axis=1) / np.sum(distance)
probabilities:確率をセットする。確率なので全部足すと1になる。
全体の距離のうち、データごとの距離の割合を求める。
その割合を probabilities変数にセットする。
距離が遠い
=probabilities変数にセットされる値が大きい
=次にセントロイドとして選ばれる確率が高い
という仕組み。
逆に言うと、近い距離のデータはセントロイドとして選ばれづらくなる。
こうやって、距離が遠いものをセントロイドとして選んでいく。
用語
クラスタの中心:セントロイド
実装演習(kNN)
上の結果はkの値が3の場合。
100×100のメッシュグリッドを作って、そのメッシュグリッドに対して
クラス分類をしている。
NumPyを使った実装による結果だが、十分にクラス分類できている。
kの値を10にしたところ、滑らかな線が描かれた。
どの程度のkが適切かは機械的に求めるのは難しい側面があるので
人間の目で結果を見て、パラメータ(kNNの場合はk)の値が適切か
判断する必要がありそう。
scikit-learnのKNeighborsClassifierクラスを使った方も実行してみた。
NumPyのときと同じグラフが描かれた。
当然だろうが、NumPyで自前で書いたものと同じアルゴリズムで
KNeighborsClassifierクラスが動作しているのであろう。
実装演習(k-means)
これは iter_max=100 の場合。
きれいにクラスタリングできている。
試しに、iter_max=2にして実行してみたところ、
それでもきれいにクラスタリングできた。
(100の場合と分類境界がほぼ同じ)
今回のデータは明確に3種類に分けられるため、
クラスタの中心を再計算する回数も少なくて済むのだろう。
逆いうと、データが明確に分けづらい場合は
クラスタの中心を再計算する回数が多く必要になるのだろう。