非線形データに普通のKMeansを使う

1,2,2,2,3,3,4,10,10,11,11,11,12,12,12,12,13,13,25,25,26,26,26,27,28,28,29,29,29,29,30,30,30,31

例えば上記のような1次元のデータがある場合を考える。ある小学校のクラスで行われた簡易テストの点数のようなイメージだ。「1点の生徒が1人、2点の生徒が3人・・・31点を取った生徒が1人」という感じである。

nonlinear2

ヒストグラムは上記のようになる。ここで色分けは意図的に行っている。

  • 赤は落ちこぼれ
  • 緑は普通の生徒
  • 黒はよくできるグループ

のように、いわゆるラベル分けを行うことができる。繰り返しになってしつこいが、これは意図的なラベル分けだ。

ここでは3つに分類すると決めており、データは人間から見ると自然に3つに(ヒストグラム上で)別れている。各グループ間は線形分離が可能だ。

このような場合、KMeansクラスタリングでk=3とすると完璧にクラスタリングしてくれる(ことが多い)。「ラベルが3種類だから、k=3とする」というごくありがちなアプローチである。

a <-c(1,2,2,2,3,3,4,10,10,11,11,11,12,12,12,12,13,13,25,25,26,26,26,27,28,28,29,29,29,29,30,30,30,31) 
> kmeans(a,3)
K-means clustering with 3 clusters of sizes 16, 11, 7

Cluster means:
[,1]
1 28.000000
2 11.545455
3 2.428571

Clustering vector:
[1] 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Within cluster sum of squares by cluster:
[1] 56.000000 10.727273 5.714286
(between_SS / total_SS = 98.1 %)

Available components:

[1] "cluster" "centers" "totss" "withinss" "tot.withinss"
[6] "betweenss" "size" "iter" "ifault"

仮に今回のケースが、ラベル有りで上記データが提供されていて、KMeansでモデルを作り、新たなデータを「落ちこぼれ」「普通」「よくできる」のいずれかに分類したいという状況だとする。この場合、データが上記kmeansの実行で得られたクラスタ中心(28, 11.5, 2.4)のどれに一番近いか?を判断するだけで良い。

しかし、ラベルが3種類ではなく、下記の2種類だったらどうなるだろうか。

nonlinear3

ここでラベルが以下の2つであるとする。

  • 緑は「普通でない生徒」
  • 赤は「普通の生徒」

突如、緑に属するデータは非線形な集まりとなってしまう。先ほどと同じようにKMeansでモデルを作り、新たなデータを分類する問題として考える場合、先ほどと同じアプローチで「ラベルが2種類だからk=2でクラスタリングしよう」と思っても当然うまくいかない。

ここで「くそっ、KMeansは非線形データに弱いんだぜ…」と考えてカーネル関数とかそっちに走るのもひとつの手だが、もっと超簡単な方法がある。というかこのブログエントリを先頭から読めば自然に気づくと思うが、「ラベルが2種類だからk=2」というのを「ラベルは2種類だけどk=3でやってみよう」とするだけである。

そして、実際の分類の際には

  • 1つめのクラスタ中心に近ければ「普通でない生徒」
  • 2つめのクラスタ中心に近ければ「普通の生徒」
  • 3つめのクラスタ中心に近ければ「普通でない生徒」

というロジックに従えばOKである。

クラスタリング結果をそのまま分類に使うのではなく、クラスタリング結果にもうひとつだけ処理を追加するだけでよい。クラスタリングはあくまでも数値処理で、人間がそれをうまく解釈してやるだけの話だ。

あまりにも簡単な話なのだが、意外と目にしない(私の探し方が悪いだけかもしれないが)ので、ブログに書いてみた。

Advertisements