froglog

プログラミングや統計の話など

PyStan で多次元混合正規分布を学習する

このエントリについて

PyStan の実行環境を用意したので、モデルパラメータ推定に使ってみました。 個人的に慣れのある多次元の混合正規分布GMM: Gaussian Mixture Model)のパラメータを学習してみます。

GMM

複数正規分布の重なりによって表される確率モデルです。 詳しくはググれ

かつて音声認識の仕事をしていたときによく触っていたという慣れがあり、このモデルを選びました。 通常は GMM といえば EM アルゴリズムによる学習が一般的なのかなと思います。 でも今回は MCMC

学習データ

多次元の正規分布にもとづく学習用データを、Python機械学習用ライブラリである scikit-learnmake_classification() メソッドで用意しました。

例えば以下は2次元かつ4混合の GMM から作られたデータのプロットです。 次元相関のある4つの2次元正規分布を見て取れるかと。(重なりあり)

f:id:soonraah:20141006010011p:plain

今回初めて使ってみたのですが、適当な実験データを作るのに sklearn.datasetメソッドはなかなか便利そうです。

PyStan によるモデルパラメータ学習

では実際に PyStan による多次元 GMM のモデルパラメータ学習をコードを交えて見ていきます。 今回は Python のコードと Stan のコードを別ファイルにしていますが、Python の中に Stan コードを文字列で埋め込むこともできます。

Stan

まず Stan のモデル定義を multi_dimensional_gmm.stan として保存します。

Stan code for multi dimension GMM with full covari ...

ちょっとググって見たのですが、多次元かつフルの共分散行列を学習できる Stan コードの例が見つからなかったので、

を参考にして多次元かつ分散を学習できるように手を加えて作りました。*1 *2

Python

上記の Stan のコードを使って実際に学習を回すための Python コードが以下になります。 make_classification() による 学習データ生成も含んでいます。

Python code to train GMM by PyStan.

ポイントとなる部分を見ていきます。

  • 33行目: 2次元かつ4混合の正規分布にもとづく学習データを1000サンプル作成します。
  • 36行目: ファイル multi_dimensional_gmm.stan のモデル定義を読み込んで C++コンパイルします。
  • 40行目: Stan の data セクションで定義されたデータを辞書形式で渡し、学習させます。学習自体はこの1行だけで書けてしまいます。
  • 42行目: 辞書ライクな形式で return された学習結果を表示させます。

コンパイル部分に結構時間がかかり、私の買ったばかりの性能とデザインを研ぎすました iMac で25秒程度要しました。 コンパイルの頻度が高いとシステム化するときに問題になりそう。

学習結果

前述のプロットの学習データのときの学習結果の出力は次のようになりました。 (適当に改行を追加しています)

OrderedDict([
    ('weights', array([ 0.35766754,  0.21940132,  0.30998937,  0.11294177])),
    ('mu', array([
        [ 0.9772859 , -0.90527383],
        [-0.93987368, -0.90560861],
        [ 1.18169255,  1.19923733],
        [-1.00850481,  1.20498538]])), 
    ('sigma', array([
       [[ 0.0873947 , -0.11510449],
        [-0.11510449,  0.87560445]],

       [[ 0.66621811,  0.84946125],
        [ 0.84946125,  1.29226115]],

       [[ 1.78483369,  1.18724188],
        [ 1.18724188,  0.99583823]],

       [[ 0.00758462, -0.04079781],
        [-0.04079781,  0.70870785]]]))])

mu つまり平均の座標がだいたいグラフプロットと合ってるのが分かるかと思います。*3

学習できているようです。

まとめ

  • PyStan の MCMC で多次元 GMM のパラメータを学習できた
  • Stan のコードを C++コンパイルするのに時間がかかる
  • scikit-learn の datasets のメソッドは適当な実験データ作るのに便利

じゃあ EM アルゴリズムと比べてどうなのか?というのが疑問ですね。 こちらはまた別のエントリで実験しようかな。

2014-10-06 追記

怪しい点があったのでデータ等を修正しました。

*1:共分散行列のサンプリングの書き方はあれでいいのか?等、怪しい部分もあるので「これは変だ」と気付いた方がいらっしゃったらご指摘いただけると嬉しいです。

*2:2014-10-06 勘違いしていたところがあったので修正。「~」によるサンプリングの部分は不要でした。

*3:実際、make_classification() はデフォルトで n 次元立方体の頂点、この場合だと (1, 1), (1, -1), (-1, 1), (-1, -1) に分布の平均を置くので概ね近い値になっています。

Mac OS X に PyStan をインストールした

このエントリについて

PyStan とは、MCMC サンプリング等を高速に実行するために C++ で実装されたプログラミング言語 StanPython インターフェースです。 このエントリでは PyStan を Mac のインストールしたときの手順を残します。

事前準備

ドキュメントによると PyStan は

に依存しているため、まずこれらをインストールします。 購入間もない Mac なので諸々一からインストールしていきました…。

Python3 をインストール

Mac に元々入っているのは 2.7 ですが、3系を使いたかったので homebrew でインストールしました。 Homebrewを使ってMacにPython3とかNumpyとかScipyとかをインストールする - 開発のヒホ を参考、というかそのままやっています。。。

brew update
brew install python3
pip3 install --upgrade setuptools
pip3 install --upgrade pip
brew linkapps

次のコマンドでバージョンが表示されれば OK。

python3 -V

エントリ投稿時点では 3.4 がインストールされますが、たぶん大丈夫でしょう。たぶん…

Cython をインストール

pip でインストールできます。

pip3 insall cython

Pythonimport してエラーが出なければ OK。

python3

>>> import cython

NumPy をインストール

同じく pip でインストールします。

pip3 install numpy

同様に import できることを確認。

PyStan インストール

依存物をインストールしたので PyStan 本体をインストールします。 これも pip でインストールできます。 pip 最高!

pip3 install pystan

import の確認もします。

PyStan を使ってみる

ドキュメントの Example 1: Eight Schools にコードサンプルが載っているのでそれをやってみます。 Eight Schools という問題設定で、元論文をすぐに見つけられなかったんですがおそらく Gelman, et al 2006 の「5 Application to the 8-schools example」あたりの話ではないかと。

テストの効果を検証するみたいな話のようですが、よくわからないままサンプルコードを実行してみます。

schools_code = """
data {
    int<lower=0> J; // number of schools
    real y[J]; // estimated treatment effects
    real<lower=0> sigma[J]; // s.e. of effect estimates
}
parameters {
    real mu;
    real<lower=0> tau;
    real eta[J];
}
transformed parameters {
    real theta[J];
    for (j in 1:J)
    theta[j] <- mu + tau * eta[j];
}
model {
    eta ~ normal(0, 1);
    y ~ normal(theta, sigma);
}
"""

schools_dat = {'J': 8,
               'y': [28,  8, -3,  7, -1,  1, 18, 12],
               'sigma': [15, 10, 16, 11,  9, 11, 10, 18]}

fit = pystan.stan(model_code=schools_code, data=schools_dat,
                  iter=1000, chains=4)

C++ コードをコンパイル中みたいなメッセージが出た後にばーっとログが流れて演算終了。 結果の fit オブジェクトを出力してみます。

print(fit)
Inference for Stan model: anon_model_95013624776d537c3cd7cd4d641c30e0.
4 chains, each with iter=1000; warmup=500; thin=1;
post-warmup draws per chain=500, total post-warmup draws=2000.

           mean se_mean     sd   2.5%    25%    50%    75%  97.5%  n_eff   Rhat
mu         7.77    0.15   5.21   -2.2   4.27   7.75  11.28  18.56   1179    1.0
tau         6.7    0.17    5.8   0.19   2.38   5.42   9.16  21.54   1120    1.0
eta[0]     0.39    0.02   0.97   -1.7  -0.24   0.39   1.02   2.25   2565    1.0
eta[1]     0.02    0.02   0.86  -1.69  -0.52 2.5e-3   0.57   1.75   2737    1.0
eta[2]    -0.23    0.02   0.96  -2.13  -0.86  -0.26    0.4   1.64   2711    1.0
eta[3]    -0.01    0.02    0.9  -1.85  -0.62   0.02   0.58   1.79   2339    1.0
eta[4]    -0.32    0.02    0.9  -2.13  -0.89  -0.33   0.25   1.49   2469    1.0
eta[5]    -0.23    0.02    0.9  -1.95  -0.83  -0.26   0.36   1.66   2523    1.0
eta[6]     0.34    0.02   0.92  -1.67  -0.19   0.35   0.94   2.07   2247    1.0
eta[7]     0.08    0.02   0.91  -1.77  -0.51   0.11   0.69   1.86   2895    1.0
theta[0]  11.31     0.2   8.38  -2.93   5.98  10.19  15.62  30.79   1775    1.0
theta[1]    8.0    0.13   6.01  -3.71    4.2    7.8  11.84  20.21   2278    1.0
theta[2]    5.8    0.16   7.93 -11.48   1.61   6.18  10.57   20.5   2414    1.0
theta[3]   7.61    0.16    6.8  -6.54   3.24   7.63  11.94  20.88   1720    1.0
theta[4]   4.92    0.15   6.45  -8.94    1.0   5.47   9.22  16.19   1817    1.0
theta[5]    6.1    0.14   7.03  -9.72   2.26   6.35   10.6  19.23   2446    1.0
theta[6]  10.52    0.15    6.7   -1.4   5.96  10.14  14.41  24.89   2068    1.0
theta[7]   8.49    0.16   7.78  -6.79   3.74   8.28  12.97  25.29   2389    1.0
lp__      -4.99     0.1   2.78 -11.67  -6.61  -4.73  -2.97  -0.53    853    1.0

Samples were drawn using NUTS(diag_e) at Sat Aug 23 14:52:02 2014.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at
convergence, Rhat=1).

なんかできてるっぽい。

Python のグラフ描画モジュールである matplotlib がインストールされていれば次のコマンドでグラフ描画できるとのことなのでやってみます。

fit.plot().show()

グラフが表示されました。

f:id:soonraah:20140823145853p:plain

ええやんええやん。

おわりに

まだ Stan 自体よく理解できていませんが、とりあえずインストールして使えることは確認できました。 勉強しながら使っていきたいと思います。(小並感)

クラスタリング結果の評価の尺度基準

このエントリについて

クラスタリングの結果を定量評価するときの基準を数年に1回ぐらい調べてる気がするのと、日本語であまりまとまった情報を見ない気がしたので挙げてみます。今回挙げるのはハード(クリスプ)クラスタリングについての指標です。後で追加するかも。

クラスタ内距離二乗和

という呼び方が正しいのかどうかわかりませんが、k-means 法の場合はこの値を繰り返し処理の結果、極小化するようになっており*1、重要な指標となります。 クラスタ内の凝集性を表現します。

\( P_k = \sum_{i=1}^k \sum_{x \in C_{i} } \left( d(x, c_i) \right) ^2 \)

\( k \): クラスタ

\( C_i \): i番目のクラスタ

\( x \): クラスタのメンバー

\( c_i \): i番目のクラスタのセントロイド

Pseudo F

Calinski and Harabasz, 1974*2 によるクラスタ間分散とクラスタ内分散の比からなる指標です。 クラスタ内距離二乗和がクラスタの凝集性のみを見ているのに対し、Pseudo F では複数のクラスタの離散性も考慮しています。 クラスタ同士は疎、かつクラスタ内は密になっている場合を良しとます。

\( Pseudo F = \frac{(T - W_k) / (k - 1)}{W_k / (n - k)} \)

\( T \): 全サンプルの距離二乗和

\( W_k \): クラスタ内距離二乗和

\( k \): クラスタ

\( n \): 全サンプル数

分子がクラスタ間分散、分母がクラスタ内分散を表します。

CCC (Cubic Clustering Criterion)

SAS による指標。*3

データの分布が均一であればクラスタリングの結果は同じ大きさの超球状のクラスタになると想定し、そこからどれだけ離れているかで評価します。 つまりデータ分布の疎密によりクラスタ結果は現実には同じ大きさの球にはならないため、そこから離れている程良いという考えのようです。(正直あまり理解できておりません…詳しくはリンク先を参照)

\( CCC = \ln \left[ \frac{1 - E(R ^ 2)}{1 - R ^ 2} \right] \times K \)

\( E(R ^ 2) \): \( R ^ 2 \)の期待値

\( R ^ 2 \): \( R ^ 2 \)(全サンプル分散およびクラスタ内分散の比??)の観測値

\( K \): variance stabilizing transformation

※サンプルベクトルを構成する次元間に強い相関あると正しく機能しないという記述もあります。

Dunn’s Index

Dunn, 1973 による指標。*4

これも Pseudo F と同じでクラスタ内の凝集性とクラスタ間の離散性の指標ですが、凝集性および離散性の捉え方が違います。 Dunn's Index ではクラスタ内の任意のサンプル間の距離により両者を定義します。

\( Dunn's Index = \min_{1 \leq i \leq k} \left \{ \min_{1 \leq j \leq k, j \neq i} \frac{ \delta (C_i, C_j)}{\max_{1 \leq l \leq k} \Delta (C_l) } \right \} \)

\( \delta (C_i, C_j) \): クラスタ\( i \)とクラスタ\( j \)の距離。2クラスタのサンプル間の最小距離で定義される

\( \Delta (C_i) \): クラスタ\( i \)の直径。クラスタ内の2サンプルの最長距離で定義される

DB's Index

Davies and Bouldin, 1979 による指標。*5

これもクラスタ内の凝集性およびクラスタ間の離散性の指標となります。

\( S_i = \left( \frac{1}{\left | C_i \right |} \sum_{x \in C_{i} } \left( d(x, c_i) \right) ^ 2 \right) ^ \frac{1}{2} \)

\( d_{ij} = d(c_i, c_j) \)

\( R_i = \max_{1 \leq j \leq k, j \neq i} \left \{ \frac{S_i + S_j}{d_{ij}} \right \} \)

\( DB's Index = \frac{1}{k} \sum_{i=1}^{k} R_i \)

\( S_i \): クラスタ\( i \)のメンバーのばらつき

\( \left | C_i \right | \): クラスタ\( i \)のサイズ

\( d_{ij} \): クラスタ\( i \)とクラスタ\( j \)の距離。セントロイド間の距離で定義

Pseudo T-square

前述の指標はクラスタリングの結果全体に対しての指標でしたが、こちらは階層型クラスタリングにおける1階層の処理、即ちクラスタのマージを評価するものです。最適っぽいクラスタ数を決める指標であるとも言えます。 この指標が小さい階層が最適らしいクラスタリング結果だということです。 Duda, Hart and Stork 2001 による考えが元となっています。*6

\( Pseudo T Square = \frac{B_{ij}}{ (W_i + W_j) / (n_i + n_j - 2) } \)

\( B_{ij} \): クラスタ\( i \)とクラスタ\( j \)間の距離二乗和

\( W_i \): クラスタ\( i \)のクラスタ内距離二乗和

\( n_i \): クラスタ\( i \)のメンバー数

まとめ

個人的には Pseudo-F が一番しっくりくる気がします。クラスタリングを空間分割の目的で使う場合、別の言い方をするとクラスタ間の離散性を気にしない場合はクラスタ内距離二乗和の方が良さそう。

誤りがあればご指摘いただければと思います。

参考

性能要件重視のシステム開発の定石について考える

このエントリについて

最近参加したとある勉強会や業務をしている上で思うところありまして。

性能要件に価値を置くようなシステムの開発において、性能面でのリスクを軽減するような進め方って?というところを考えてみました。

機能要件と性能要件

私はいわゆるシステム開発にはそれほど詳しくはないんだけど、システム開発のプロジェクトには2種類あるのではと考えています。一つは 機能要件 にウェイトをおくプロジェクトで、企業の会計システムなどおそらくシステム開発というと多くはこちらに属するのではと思います。*1

一方、非機能要件、特に 性能要件 がそのシステムの価値の大きな部分を占める場合もあります。 いわゆるビッグデータ的な話のプロジェクトはこちらに属することが多いのではないでしょうか。 機能要件に比べ性能要件は「やってみないと分からない」感が強く、性能要件を達成できるかが読みにくく不透明であることが挙げられます。(もちろん機能要件を満たすのも簡単ではありませんが)

つまりプロジェクトスタート時点では「性能要件を満たせないかもしれない」というリスクが常にあるわけです。 であれば性能要件重視のプロジェクトはそのリスクを考慮した進め方をしないといけないはず。 その進め方の定石ってだいたい次のような感じになるんじゃないでしょうか??

性能要件重視のシステム開発

最適化や予測、パターン認識のようなソリューションのシステムについて考えます。

プロジェクト全体の進行

  1. 要件定義
    • KPI の合意
  2. データ収集
  3. データ分析
    • 目的を達成するための手法にあたりをつける
    • 足りないデータがないか、あれば収集する
    • オフライン評価、オンライン評価の設計
  4. オフライン評価
    • P: テスト対象の手法やアルゴリズム、特徴量等を決める
    • D: テストデータについて上記手法の実施や統計モデルの学習など
    • C: オフライン評価用の KPI で評価
    • A: 結果によって次のイタレーションの方向性を決める
  5. システム開発
    • 設計: どこまでのチューニングを許容するか?
    • 実装: ゴリゴリ
    • テスト: ここでは機能についてのテスト
  6. リリース
  7. オンライン評価
    • P: パラメータの変更、手法の入れ替え等
    • D: 実環境での運用
    • C: オンライン評価用の KPI で評価
    • A: 結果によって次のイタレーションの方向性を決める

以下、この内のデータ分析・オフライン評価・オンライン評価について述べます。

データ分析

ここのデータ分析は「実現の手法ありき」の分析ではなく、データを見ることによりどの手法が妥当(っぽい)かを決めるための分析です。 ここが「実現の手法ありき」になってしまっていると「分析ツールにデータをつっこんでみました。こんな結果出ました」というだけの分析になりかねません。これではリスクへの備えになりません。

また、この時点で後で出てくるオンライン評価とオフライン評価の設計をしておきます。 それぞれについて KPI は何か、納得感のある評価をするにはどういうデータ・手順が必要か、等を決めます。

オフライン評価

ここがないとぶっつけ本番で商用運用を始めることになり、性能要件が未達だった場合は非常につらいことになります。 そのリスクを避けるためにも、本開発が始める前に実装しようとしている手法の妥当性をここで見ておきます。

また、PDCA サイクルを何回か回して試行錯誤しておくことで手法を叩き上げると同時に、実装のバリエーションの幅が見えてくるのではないでしょうか。

オフライン評価が難しい場合ももちろんありますが、ある程度のシミュレーションはできる場合が多いと思います。(というのもオフライン評価ができてない、頭にないことが多いように思われるためです) 場合によっては評価データを別途収集するような判断もありえますが、そこはコストとリスクのバランスで決めます。

オンライン評価

ここでも同じように PDCA サイクルを回しますが、最後の詰めのチューニングになります。システムの実装を変えるような変更は好ましくなく、できるだけパラメータチューニング程度で済ませられればよいでしょう。*2

また、運用しながら評価を回すことになるのでできるだけ迅速に一つのパラメータセットを評価できる必要があります。Web システムの何かの最適化みたいな話であれば A/B テストは必須でしょう。

何かのメトリクスを改善するというタスクにおいて、できるだけ短い期間で実験結果を得、トライ&エラーをできるだけたくさん回す ことが改善効率に大きく寄与するというのはシステム開発に限った話ではなく、言うまでもない真理です。インターネッツのエライ人たちも言っています。*3 *4

まとめ

偉そうに書いてますが、性能要件未達のリスクを考慮していくと普通はこれに近いプロジェクト運営に自然となっていくのでは…と思っています。 というのも最初に書いた勉強会で見た発表や、かつて携わった音声認識のプロジェクト*5でも似た感じだったからです。

ただし、上に書いたのが理想的な進め方なのかは分かりません。もっとイケてる方法があれば教えて欲しいです。 また、すべてのシステムで前述のような進め方ができるわけでもありません。例えば組込みシステムだとオンライン評価はできないわけで。

できるだけ性能面のリスクを軽減して、ベンダーもクライアントもみんなが幸せになれるようにやっていけるといいんだけど。

*1:もちろんそういったシステムでもレスポンスタイムやスループットなど性能要件も含まれることは理解しています

*2:とはいえ性能未達なら実装を変更しないといけなくなるかもしれません…

*3:iPad登場後の出版社のデジタル戦略とは?

*4:ビッグデータというか、根拠を元に主張をするという行動原理の話

*5:認識性能がそのまま UX に影響を与える、性能重視案件

k-means 法の注意点とオレオレベストプラクティス

このエントリについて

クラスタリングでよく使われている k-means 法ですが、最近は BI ツールでサポートされていて自称データサイエンティストさんでも誰でもデータを突っ込めば何かしらのクラスタリング結果が得られるわけです。

が、手法の特徴を把握せずに使ってるとひどいクラスタリング結果を量産してしまうことになりかねないよってことと、ではどうすれば失敗を減らせるかというところを書きます。

k-means 法の説明はここではしません。 ある程度どういうものか、何のために使うものかを理解している前提で話を進めますが、 不安のある人は 神嶌先生のサイト なんか見るといいよ。 神嶌先生最高!

ツール紹介

ということで k-means 法の癖を見るためのツール を用意しました。

f:id:soonraah:20140407041525p:plain

左の散布図で2次元のサンプルデータをユークリッド距離の k-means 法でクラスタリングしていく過程を見ることができます。 サンプルデータの分布とクラスタ数 k は複数から選択できるようにしました。

また、右の折れ線グラフではクラスタのセントロイドからの各サンプルデータまでの距離の2乗の平均、つまり前述の 神嶌先生のサイト における k-means 法の評価関数(をデータ数で割ったもの) *1 のステップごとの推移を表しています。 ランダムの初期値の取り方により、違う推移をしていくことが観察できます。

ちなみにグラフ描画には D3.jsC3.js を使いました。D3.js は説明不要ですね。C3.js はグラフ描画用の D3.js ラッパーライブラリで、今回初めて使ってみました。*2

以下、いくつかの分布で k-means の性質を述べます。

一様分布(Uniform)

f:id:soonraah:20140407043348p:plain

一様ランダムなサンプルデータ分布です。

まずはこちらでいろいろ遊んでもらえればと思います。

3つの2次元正規分布(3 Gaussians)

f:id:soonraah:20140407044140p:plain

3つの2次元正規分布の確率からなるサンプルデータ分布です。

これを Number of clusters = 3 で何回か実行してみてください。 右の折れ線の収束時の y 軸の高さが、2つの高さに収束するはずです。 このことは、 初期値のランダムの取り方によってクラスタの凝集度が大きく違ってくる ということを示します。

3つの円状分布(3 Circles)

f:id:soonraah:20140407045412p:plain

3つの円状の分布からなるサンプルデータ分布です。

見た感じでは結構はっきりと分かれていますね。 これなら Number of clusters = 3 で3つのクラスタにも簡単に分けられるはず。

…と思ったら大間違いで、人間の感覚どおりにきれいに3つに分けることはできません。 ユークリッド距離等の距離尺度を用いる場合、k-means 法ではクラスタ境界はセントロイド同士を結ぶ直線の二等分線となります。 二等分線であり直線上の疎密は考慮しないので、そのような結果となります。 *3

2つの離れた分布(Separated)

f:id:soonraah:20140407050457p:plain

少量データからなる2つの隔てられたサンプルデータ分布です。

これを Number of clusters = 2 で2つのクラスタに分けてみてください。 こんな簡単な分布がきれいに分けれない訳がない…と思いますか? これが 1/7 の確率で予想外のクラスタ分布になります。やってみてください。

k-means 法の運用

オレオレベストプラクティス

以上を踏まえると「分析で k-means 法を使わなくちゃいけない><」ってなったときは、次のような運用が安全だと言えます。

  • ループはできる限り収束するまで回す
  • ある k においてはランダムで初期値を変えて複数回実行し、クラスタ内距離平均のような KPI で最適なクラスタの分け方をみつける
  • いくつかの k について上記を試し、おさまりの良さそうな k を決定する

ベストプラクティスとか書きましたが、k-means の性質が分かっていればまあ普通は上記のような方法になるんじゃないの。

クラスタリングの KPI

KPI については今回折れ線グラフで出したものが一番シンプルなものですが、クラスタ内の凝集度だけでなくクラスタ間の離れ具合も考慮した Pseudo-FSAS で使われている CCC 、Mahout で採用されている CDbw 等、いろいろあるようです。 これらのどれかを使って 定量的に 評価しないとクラスタリング結果のクオリティは安定しません。

最後に

k-means 法って扱いにくいからやらない方がいいよ…ということではなく、ハサミも使い方分かってないと手を切っちゃいますよね。分析で使う道具についても知っといた方がいいよという話でした。

(ピュアな k-means 法をdisるのは別のエントリでやります^^)

*1:クラスタの凝集度合いのようなものですね。小さい程いいわけです。

*2:グラフの形式が違うのは別々に作ったためで、あまり気にしないでください…

*3:マハラノビス距離のような分布の広がりを考慮した距離尺度を使うか、階層型クラスタリングを使えばこの分布をきれいに分けることができます。