
教師なし学習であるクラスタリングにはk-means法という手法があります。ここではk-means法のアルゴリズム概要を説明し、簡単に計算が可能なscikit-learnを使ったPythonによるサンプルコードを紹介します。
こんにちは。wat(@watlablog)です。本日はクラスタリングの基礎!k-means法の概要とPythonコードを紹介します!
k-means法によるクラスタリング概要
k-means法とは?
k-means法とは、クラスタリングを行うアルゴリズムの1つで教師なし学習法の中の一手法でもあります。
当ブログでは過去に、
・決定木による分類
・ランダムフォレストによる分類
・ロジスティック回帰による分類
・サポートベクターマシンによる分類
・サポートベクターマシンによる回帰
・k近傍法による分類
…と、様々な機械学習手法を紹介してきましたが、これらのどれもが教師あり学習でした。
教師あり学習とは、トレーニングデータと呼ばれる正解データを用いて学習を行う手法で、分類問題であればデータと紐付けになっているクラスラベル、回帰問題であればデータの値自体が目指すべき正解になります。
一方教師なし学習とは、トレーニングデータを使わない、つまり正解がない状態からデータの本質的な構造を抽出する手法です。
代表例としてクラスタリング(クラスター分析)が挙げられます。
他には統計の分野でよく聞く主成分分析とかも教師なし学習の1つとされていますね。
クラスタリングとは、データ群から特徴的な構造を抽出してデータを複数のクラスタ(まとまり)に分けることを意味します。
例えば、以下のような2変数で表現されたプロットがあるとしましょう。

僕達人間の目で見ると、「なんとなく」…

…このように分かれているような気がしませんか?(しない?)
感覚はさておき、上図のようにデータ群をあるルールに沿ってグルーピングするのがクラスタリングです。
k-means法とは、このいくつかのクラスタをk個と設定し、データの重心を探索しながら分類していく方法です。
言葉では中々イメージが湧かないと思いますので、まずはイメージを付けましょう!
k-means法の手順(numpyコードで解説)
動画でk-means法の手順を理解しよう!
ざっくりとした手順を直感的に理解するためには、言葉よりも動画の方が効率が良いと思いましたので、以下にYoutubeにアップロードしたk-means法のプロセス可視化動画を示します。
それではこれから動画の内容詳細を説明していきます。
①k個のクラスタ中心をランダムに生成する
まず始めに、k-means法のハイパーパラメータであるクラスタ数
最初は特に情報が無いので、データ群上にランダムに
※次元数が増えても考え方は同じです。

この点は本来クラスタの中心を意味する点となりますが、最初はとても中心には見えません。
②各データを最も近いクラスタに属するようにする
次に、各データとそれぞれのクラスタ中心との距離を計算して、各データと最も近いクラスタと関連をつけます(ここでは黒い線で表現しています)。

クラスタ中心はランダムな点を使っているので、中にはどの点から見ても遠い点となる場合もありますがこの点は次に再度ランダムに決定します。
③クラスタ中心をデータの重心に移動させる
仮でもデータとクラスタ中心を関連付けした後は、クラスタ中心を自身のデータ群の重心(平均)に移動させます。この時に平均計算をしていることがk-means法(k平均法)の由来になります。

④データを再度クラスタと繋ぎ直す
クラスタ中心をデータ群の重心に移動させた後は、データとクラスタ中心の距離関係が変わってしまうので再度距離計算をし直し関連付けを更新します。

先ほどどのデータとも距離が遠かった点も、何度かランダム生成を繰り返すとそのうちどこかのデータに繋がります。
⑤クラスタ中心が動かなくなるまで繰り返す
上記計算をクラスタの中心が動かなくなるまで、具体的には移動量があるトレランスを下回るまで繰り返します。

以下が最終的に得られたデータのクラスです。ちょっとオシイ気もしますが、特に正解ラベルがなくても単純なアルゴリズムでここまで分類することができました。

おまけ:numpyによるk-means法コード
先ほどまでの図はPythonのnumpyを使ってコーディングしたk-means法(細かい所を見ると、厳密には違うかも知れませんが)からプロットを画像にしていったものです。
コードの内容はコード内のコメントをご覧下さい。是非多変数へ対応した一般化をしたり、いじって遊んでみて下さい。
Python/scikit-learnによるk-means法コード
全コード
先ほどまではアルゴリズムの理解を深めるためにあえて車輪の再発明をしてみましたが、Pythonには先人が積み上げた知識をライブラリにした外部パッケージがあるので、通常はこれを使います。
ここではscikit-learnという機械学習ライブラリを使ってk-means法によるクラスタリングをしてみます。
以下がscikit-learnによるk-means法のサンプルコードです。
サンプルデータ生成やグラフ表示部分を除けば、クラスタリング部分はわずか数行です。
k-means法を使うために、from sklearn.cluster import KMeansを宣言します。KMeansのn_clustersでクラスタ数
.fit_predictを使うことで配列としてクラス分類結果を受け取ることができ、この配列をpandasデータフレーム置換したものが最終的なアウトプットです。
実行結果
以下が上記コードの実行結果です。先ほど自作したnumpy版の結果とほぼ一致した結果を得ることができました(データはランダム生成なので若干違うのは仕方ない)。

k-means法はデータが広く分布(分散が大きい)しているとうまくクラスタリングしてくれないような結果ですね。これを解決する別のアルゴリズムとかもあるのかな?
Twitterでは混合ガウスモデルはどうか?とアドバイスを頂きました!別手法についてはまたの機会にまとめようと思います!
まとめ
本ページでは教師なし学習の1つであるk-means法によるクラスタリングの概要を説明しました。
説明にはライブラリを利用するだけでなく、あえてnumpyで2変数の場合のクラスタリングを実装してみることで理解を深めることに挑戦しました。
実際にコーディングし、動画でk-means法のプロセスを眺めているとどのような変化をしているのかが一目瞭然でした。
また、最後にscikit-learnによるk-means法のコードも紹介し、ライブラリを使うことで非常に効率的なコーディングができるということも体感しました。
教師なし学習と言うと難しそうなイメージでしたが、やってみると案外簡単でしたね!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
コメント