静かなる名辞

pythonとプログラミングのこと



【python】skfuzzyのFuzzy c-meansでソフトクラスタリング

 Fuzzy c-meansはソフトクラスタリングの手法です。

 pythonではscikit-fuzzyというライブラリで利用できるようです。ということで、実際に使ってみました。

 基本的な理論はこちらのサイトなどを参考にしてください。

ファジィc-means法 - 機械学習の「朱鷺の杜Wiki」

sklearnではなかった

 ドキュメントはここです。
Module: cluster — skfuzzy v0.2 docs

 親切なことに使用例のページもあります。
Fuzzy c-means clustering — skfuzzy v0.2 docs

 一読してわかるとおり、sklearnライクなインターフェースがある訳ではないようです。それも一つの方針として悪くはないと思いますが、ちょっとカルチャーショックを受けました。

基本的な使い方

 sklearnライクではないので、使い方を理解するまで手間取りました。簡単に(コメントで)説明しておきます。

# cmeans『関数』をimportする
# 間違ってもクラスなどではないことを理解すること
from skfuzzy.cluster import cmeans

# dataは(データ数,次元数)のいつもの特徴量
# が、転置して渡してやる必要がある
# 5つのパラメタは省略できない。詳しくは後述
cm_result = cmeans(data.T, 3, 2, 0.003, 10000)
# 返り値も実際は7つくらい返っている
# 必要なものだけ使う

 率直な感想は「作りが古いなぁ・・・」です。「sklearn? なにそれ食えるの。オブジェクト指向? 知らんよ」みたいな。別に使う側としてはどんなインターフェースでも、解析アルゴリズムがちゃんと走れば良いので、文句言うつもりはないんですが。それでも正直なところ、ちょっと引きました。

 とりあえずパラメタと返り値について説明します。上記ドキュメントを適当に(省略しつつ)和訳しただけなので、ちゃんと使いたい人はドキュメントを読んで下さい。

パラメタ

  • data : 2d array, size (S, N)

 データ。Sはデータの次元数、Nはデータ数です。

  • c : int

 クラスタ

  • m : float

 c-meansのパラメタ。詳しくは上の理論のページを読んで下さい。変えたときの変化は後で見せます。

  • error : float

 fuzzy c-meansは処理を繰り返して収束させていく系のアルゴリズムなので、こういうものが必要になります。エラー率が一定以下になったらループを抜ける訳です。理論をちゃんと勉強していないので、エラー率の計算方法とか私は知りませんけれど。

  • maxiter : int

 最大繰り返し回数。

  • init : 2d array, size (S, N)

 これは省略できます。計算に使う初期値です。省略するとランダム配列にされます。普通「よい初期値」なんて持ってないので、省略して使うことになると思います。

  • seed : int

 initが省略されたときのランダム初期化で使うseedです。

返り値

  • cntr : 2d array, size (S, c)

 各クラスタの中心。

  • u : 2d array, (S, N)

 各データがどのクラスタに割り当てられたかを比率で示した行列です。要するにこれがc-meansの結果です。あと、ドキュメントには(S, N)って書いてあるけど、これはどう考えても(c, N)の間違いです。

  • u0 : 2d array, (S, N)

 uの初期値みたいなことが書いてある。

  • d : 2d array, (S, N)

 「Final Euclidian distance matrix.」。クラスタ中心に対する距離ってことか?

  • jm : 1d array, length P

 「Objective function history.」だって。さっぱりわからない。

  • p : int

 ループが回った回数

  • fpc : float

 「Final fuzzy partition coefficient.」

 まあ、要するに適当な引数で呼び出してあげて、実質的に使う返り値はuだけということです・・・。

 とにかく使い方はわかったので、実験してみましょう。

実験

 irisでやってみます。irisは4次元データですが、4次元だと見づらいのでPCAで2次元に落とし、2次元空間上で3クラスタ(irisが3種類のアヤメの花のデータなので)にクラスタリングすることにします。

 結果として、

  1. 元のデータを色分けした絵
  2. k-meansでクラスタリングした結果(比較用)
  3. mを1.5, 2, 3, 4, 5で変化させたときの結果それぞれ

 を得ることにし、考察します。

 実験に使ったソースコードは記事の最後に付録として載せます。次の章で先に結果を見せます。

結果

 1つずつ見せます

元のデータ

f:id:hayataka2049:20180303195615p:plain
 似たような絵を何回も見たことがあります。いつも感じることですが、irisは綺麗なデータで良い子だと思います。

k-means

f:id:hayataka2049:20180303195619p:plain
 上とはクラスタの色が違いますが、気にしないでください。以下のデータでも(出力するたびにクラスタ番号変わるので)色はバラバラです。

 右側の境界をうまく捉えられていませんが(クラスタリングだから当たり前)、それを除けば真っ当な結果に見えます。

Fuzzy c-means

 上から順にm=1.5, 2, 3, 4, 5です。各クラスタへの帰属の度合いをそのままRGBにしました。

f:id:hayataka2049:20180303195624p:plain


m=1.5

f:id:hayataka2049:20180303195628p:plain


m=2

f:id:hayataka2049:20180303195634p:plain


m=3

f:id:hayataka2049:20180303195639p:plain


m=4

f:id:hayataka2049:20180303195644p:plain


m=5

 少しずつ色が暗くなっていく傾向にありますが、これは「どのクラスタにも同程度に帰属する」みたいな結果になっていることを表します。m=1.5のときは[0.7, 0.2, 0.1]みたいな結果が、m=5のときは[0.4, 0.3, 0.3]みたいな結果が得られていると解釈してください。

 どの程度のmを設定するとちょうど良いのか・・・? 私にはわかりません。要するにmを小さくするとシャープに切れ、大きくするとゆるーく移り変わるってことなんですが。適当に決めるしかないってことなのかな。

 それはそうとして、よく見ると各クラスタの中心付近が(相対的に)鮮明な色になっていて、クラスタ中心から外れると(正確には他のクラスタ中心に接近していくと)色が混ざり合うのがお分かりいただけたでしょか? これがソフトクラスタリングの成果です。

まとめ

 とりあえず、使える(意図したとおり動かせる)のはわかりました。

 何に使えるかは・・・ごめんなさい、思いつきそうで思いつかなかったです。

 一応フォローしておくと、ソフトクラスタリング自体は「高次元の特徴量を相対的に低次元に持ってくる」とか「元の空間の情報を保持したまままったく別の空間に移す」みたいな用途のために使われることがあるようです(各クラスタへの帰属度合いを新たな特徴量とする)。たとえばこんな応用があるらしいです。

qiita.com

 ただ、上のページでは混合正規分布モデルという別の手法を使って実装していますけど・・・。どっちが良いんだろう? ぶっちゃけ謎(たぶん既存の知見があるんだろうけど)。そのへんも含めて今後検討していきたいところです。

※追記

 混合正規分布モデルでもやりました。こちらの記事をご参照ください。
hayataka2049.hatenablog.jp

付録

 実験に使ったソースコードです。python3系で必要なパッケージを入れればそのまま動くと思います。