星空のクラスタリング

クラスタリングクラスター分析)とは、多数のデータの集まりを、似通ったもの同士集めてグループ分けする統計手法です。
例えて言うなれば、星をグループ分けして星座を作るようなものです。
・・・ならば、星のデータをクラスタリングすれば、コンピュータが自動的に星座を作ってくれるのか?
試してみまみした。

星のデータは、以下から入手しました。
* プラネタリウムを作ってみよう! : 星のデータの入手方法
>>http://www.megastar-net.com/school/dataofstar.html
どうもありがとうございます!
(トップページを見たら「このコンテンツは閉鎖しました。」となっていました。ちょっと残念です。)
このデータをプロットした全天図です。

ピンク色が夏の大三角形(織姫、彦星)、黄緑色が冬の大三角形北極星は画面右上。
ベテルギウス」のところにオリオン座があって、「アンタレス」のところにさそり座があります。

このデータをクラスタリングにかける訳なのですが、幾つか困った問題があります。
問題1.明るい星と暗い星(1等星と5等星)の違いをどのように表すか?
問題2.全天は球面なので、図の右と左、上と下は本来つながっているのだが、データの上ではつながっていない。
問題3.全天は球面なので、この図はちょうど世界地図(メルカトル図法)のように、実際よりも上と下が大き目に表示されている。

問題1.
 1等星は5等星の5倍の重みを持つものと考えて、1等星のデータを5個コピーして増やしました。
 2等星は4個コピー、3等星は3個コピー・・・5等星は1個のまま。
 こんな方法が果たして妥当かどうか微妙ですが、とりあえず良しとします。
問題2.3.
 とりあえず無視!
 まあ、画面の縁のあたりの結果は見ないということで。

以上の問題アリという前提で、データをR言語のクラスター分析にかけてみました。
R言語上で、以下のスクリプトを実行します。

# Excel のデータをR に取り込むには?
excel.w <- function(nc){ matrix(scan("clipboard"), byrow=TRUE, ncol=nc) }

# 使い方
# (1): Excel の必要なデータ範囲をコピーする.
# (2): excel.w 関数を起動する. 引数は,列数を表す数値一つだけ, 例えば2列なら excel.w(2)
x1 <- excel.w( 2 )

# ウォード法でクラスタリング
hc <- hclust( dist(x1), "ward" )

# クラスタリングの過程(デンドログラム)を表示してみる
plot( hc )

# 星座の数は 88 個ということで、88クラスタに分類
result <- cutree( hc, k=88 )

# 結果をファイルに書き出し
write( result, "Clust88_ward.txt", ncolumns=1 )

その結果できあがった、さそり座とオリオン座近辺の様子です。
同じ色が付いている星は、同じクラスタ(グループ)に属しています。
(色は8色しか使っていないので、つながっていない同色は別のクラスタです。)
* ウォード法 --(クラスタ内の分散が最小となるようにグループ分けする方法)

さそり座は上半身と下半身で2分されていますね。
オリオン座も2つに分かれていて、オリオンの足と大犬座の頭が合わさって1つになっています。
ところで、クラスタリングには様々な方法があります。
方法の違いによって結果がどう変わるのか、片っ端から試してみました。

* 最近隣法 -- (最も近い点同士をクラスタ間の距離と見なす方法)

2つの星座とも、同じ色で塗りつぶされています。
実はこれ、1つの巨大クラスタが全天のほとんどを占めている状態です。
この方法だと、しばし巨大クラスタが出現するようです。

* 最遠隣法 -- (最も遠い点同士をクラスタ間の距離と見なす方法)

上の方法の逆です。
2つの星座ともバラバラで、まとまりが無い感じです。

* 群平均法 -- (全ての点間の距離の平均をクラスタ間の距離と見なす方法)

さそり座は2つに分かれた。
オリオン座と、大犬座、小犬座は、わりといい線いっている。

* 重心法 -- (クラスタ重心間の距離を、クラスタ間の距離と見なす方法)

さそり座は尻尾がちぎれた、あと一歩。
オリオン座はちょっと大き過ぎ。

* メディアン法 -- (クラスタの中央値の間の距離を、クラスタ間の距離と見なす方法)

いまひとつ、グダグダな感じ。

以上、それぞれ結果は少しずつ異なっているのですが、星座にドンピシャリと一致する方法はありませんでした。
ここまでの方法は「階層クラスター分析」と言って、
・まずデータの点同士をつなぎ合わせて小さいクラスターを作り、
・小さいクラスター同士をつなぎ合わせて、徐々に大きなクラスタを作り上げる、
といったボトムアップ方式でした。
これとは別の考え方で、全体を一気に見渡してクラスタリングを進める「非階層クラスター分析」という手法もあります。
ついでに、そっちも試してみます。
非階層クラスター分析として、R言語には k-means という手法が用意されています。

# k-meansで 88個のクラスタを生成
km <- kmeans( x1, 88 )

# 結果をファイルに書き出し
write(km$cluster, "Clust88_kmeans.txt", ncolumns=1)

* k-means (R言語:ユークリッド距離)

これはこれで、独特のクラスタができました。
さそり座が大きく3分割されたのは、これが初めて。

クラスタリングとは、距離の近いもの同士の「お団子」を作る作業なので、「丸い塊」ができやすいように思います。
一方、人間が星座を形作るときには「星の並び」、つまり1方向に連なっていることが大きな要因なのではないでしょうか。
つまり、さそり座のような細長い列に対してクラスタリングは不向きなのかも。
そう考えて、さらに別の方法を探求しました。
最近流行りのビッグデータを処理するライブラリに「Apache Mahout」があります。
調べてみると、この Mahoutに搭載されているクラスタリング機能には、
データ間の距離を角度で評価する「コサイン距離(CosineDistanceMesure)」が用意されています。
さらに、長さと角度の両方を評価する「谷本距離(TanimotoDistanceMesure)」というものもありました。
これ、いけそうなので、試してみました。

まずはR言語と同様の、k-means(ユークリッド距離)を Mahoutでも試してみます。
* k-means (Mahout:ユークリッド距離)

同じアルゴリズムであるにも関わらず、結果は微妙に変わっています。
k-means の初期値を乱数で選んでいるので、その影響かと思われます。

次に、コサイン距離でやってみます。
* k-means (Mahout:コサイン距離)

結果、巨大なクラスタができました。
上に挙げた最近隣法と似たような状況です。
その一方で、巨大クラスタからあぶれた大犬座付近はカラフルになっています。

最後に、谷本距離。
* k-means (Mahout:谷本距離)

オリオン座は、これまでの中で最も良い出来です。
さそり座も、まあまあ良し。
その一方で、大犬座と小犬座は一体化している。

ということで、とりあえず試せるクラスタリングを片っ端から試してみたのですが、
残念ながら「これが星座だっ!」と言えるような結果は得られませんでした。
きっと星座とは単純機械的な方法で形作られたのではなく、もっと人間的な要因が作用した結果なのではないかと察せられます。

Mahoutのプログラムについては、以下の本を丸写ししました。

Mahoutイン・アクション

Mahoutイン・アクション