これまでのブログで示してきたように、JMPでPython連携を使うメリットは、Pythonのパッケージを利用して、JMPに搭載されていない機能や分析手法を使えるようになることです。
今回はその例として、密度ベースのクラスタリング手法 HDBSCAN をJMPのPython連携で実現する方法を扱います。JMPにはk-means法などのクラスター分析はありますが、HDBSCANは搭載されていません。
さらに前回紹介したダイアログと組み合わせます。ダイアログでは変数(列)の指定もできます。つまり、クラスタリングに使う変数をその場で選び、パラメータの値も指定して実行できるということです。JMPの分析プラットフォームとほぼ同じ操作感でHDBSCANを使うことができます。

HDBSCANとは
HDBSCANは、データの「密度」に注目してクラスターを見つける手法です。データ点が密集している領域を1つのクラスターとみなし、密度の低い領域を境界としてデータを区切っていきます。
HDBSCANでは、事前にクラスター数を指定する必要がなく、データから自動的に決まります。また、外れ値をノイズとして分離できるところが大きな特徴です。k-means法などのクラスタリング手法では、指定したクラスター数に対して、外れ値も必ずどこかのクラスターに分類されます。これに対しHDBSCANでは、クラスターに属さない点をノイズとして扱います。
クラスター数を指定しない代わりに、「どのくらいの密集をクラスターと認めるか」を決める2つのパラメータがあります。
min_cluster_size:クラスターとして認める最小のデータ点の数
これ未満の小さな集まりはクラスターと見なされません。値を大きくすると小さなクラスターが認められなくなるため、クラスター数は少なくなる傾向があります。
min_samples:密度を測るときに参照する近傍点の数
大きいほど密度の判定が保守的になり、ノイズ(-1)が増えます。外れ値と判定するときの厳しさを指定するとお考えください。
Pythonを起点としたコード(.py)
ダイアログを作成する前に、まずはPythonを起点とした方法(.py)でHDBSCANの部分を書いてみます。
乱数を使って疑似的に作成したサンプルデータ「HDBSCAN_sample.jmp」(1,000行、連続尺度6列のデータ、本ブログに添付)を開いた状態で、.py(Example2_HDBSCAN.py)を実行すると、「X1」~「X6」を使ったHDBSCANが実行されます。
以下が、コードのメイン部分です。JMPの列「X1」~「X6」をpandasのDataFrame(表形式のデータ構造)に変換し、データの標準化を行ってから、HDBSCANを実行しています。

※このコードの実行には、事前にscikit-learnとhdbscanをJMPのPython環境にインストールしておく必要があります。
実行すると、データテーブルに3つの列が追加されます。
- Cluster:所属するクラスターの番号を保存します(名義尺度)。-1 はどこにも属さないノイズ(外れ値)を示します。
- Cluster_Prob:そのクラスターへの所属の強さ(0〜1)です。「所属確率」と訳されますが、正確には1に近いほどクラスターの中核、0に近いほど境界付近にあることを示す指標です。
- Outlier_Score:周囲の密度に対してどれだけ孤立しているかを表すスコア(0〜1)です。高いほど外れ値らしいと判断します。

JMPで探索的に分析する
ここから先はJMPの機能を用います。まずデータテーブルで、クラスターによるマーカーの色分け([行] > [列の値による色/マーカー分け])を行うと、他の分析でも群の違いが一目でわかるようになります。
主成分分析を実行し、スコアプロットを見ると、3つのクラスターがきれいに分離し、赤色(-1)の点がどの群からも離れて散らばっている様子が確認できます。

[多変量] > [多変量の相関]により多変量の外れ値分析を行うと、このデータがシミュレーションによる疑似的なものであることもわかります。Mahalanobisの距離のプロットで行番号の順にきれいに色が分かれているのは、群ごとにまとめて生成されたデータだからです。

ダイアログで汎用的なツールに(.jsl)
ここまでのコードは、変数が「X1」~「X6」に固定され、パラメータの値もコードに直接書き込まれています。別のデータで使うには、そのつど書き換えが必要です。
そこでダイアログを使い、列の選択と min_cluster_size / min_samples の指定ができるようにします。ダイアログはJSLでしか作れないため、ここからはJSLを起点としたコード(Example2_HDBSCAN.jsl)になります。要点は2つです。
1. ダイアログ部分
- Col List Box( All, … ):データテーブルのすべての列をダイアログに表示します(左側のリスト)。
- Col List Box( Numeric, … ):選択された列を受け取る側のリストです(右側のリスト)。Numeric の指定により、数値列だけを受け付けます。
- Button Box( " > " ):左のリストで選択中の列を、右のリストに追加します。
// ダイアログの起動
nw = New Window( "HDBSCAN Settings",
<<Modal,
<<On Validate( N Items( xList << Get Items ) >= 2 ),
V List Box(
H List Box(
Panel Box( "Columns",
srcList = Col List Box( All, width( 180 ), nlines( 12 ) )
),
V Center Box(
Button Box( " > ", xList << Append( srcList << Get Selected ) )
),
Panel Box( "Variables for HDBSCAN",
xList = Col List Box( Numeric, Min Items( 2 ), width( 180 ), nlines( 12 ) )
)
),
Panel Box( "Parameters",
H List Box(
Text Box( "min_cluster_size " ), mcsBox = Number Edit Box( 30, 5 ),
Spacer Box( Size( 24, 0 ) ),
Text Box( "min_samples " ), msBox = Number Edit Box( 10, 5 )
)
),
Button Box( "OK",
selCols = xList << Get Items;
mcsV = mcsBox << Get;
msV = msBox << Get;
)
)
);
2.Pythonの結果を受け取り、列として追加
ダイアログで選択した列やパラメータの情報を、Python Send() を使ってPythonに送付します。Python側では、この変数を使ってhdbscanパッケージによるクラスタリングを実行します。
Python Send( selCols );
Python Send( mcsV );
Python Send( msV );
この後の Python Get() は Python Send() の逆で、Python側の変数をJSLに取り込みます。これにより、JMPのデータテーブルに新しい列が作成できます。
// Python結果の受け取り、列の追加
labs = Python Get( labels );
prb = Python Get( probs );
outs = Python Get( outliers );
cCol = dt << New Column( "Cluster", Numeric, Nominal, Set Values( Matrix( labs ) ) );
pCol = dt << New Column( "Cluster_Prob", Numeric, Continuous, Set Values( Matrix( prb ) ) );
oCol = dt << New Column( "Outlier_Score", Numeric, Continuous, Set Values( Matrix( outs ) ) );
「HDBSCAN_sample.jmp」に対してこのJSLコードを実行すると、ダイアログから、例えば「X2」「X3」「X4」「X5」の4つの変数だけを対象にクラスタリングすることができます。
ダイアログを付けたことで、このデータ以外にも同じスクリプトを適用できます。JMPのサンプルデータ「Powder Metallurgy.jmp」の「P1」~「P5」の5つの連続変数を使い、行数に合わせて min_cluster_size を300、min_samples を30に変更してみます。

[OK]ボタンをクリックすると、主成分分析のレポートなどが表示されます。

この例のように、JMPにはない手法の計算処理はPythonのパッケージに任せ、結果の解釈と探索はJMPで行う。そして、その操作はダイアログにまとめ、変数を自由に選べるようにする。このようにして、JMPユーザーが使える汎用的なツールを作ることができます。
全4回のまとめ
全4回にわたり、JMPのPython統合機能で「結局何ができるのか」を、World Bankからのデータ取得と、HDBSCANによるクラスタリングという2つの具体例に沿って説明してきました。
これらの例に共通するのは、JMPに搭載されていない機能や分析手法はPythonのパッケージに任せ、その結果はJMPのデータテーブルとレポートで探索・可視化することです。
さらに、条件や変数の指定をJSLのダイアログにまとめれば、コードを書き換えることなく、誰でも繰り返し使える汎用的なツールになります。PythonとJMPそれぞれの得意分野を組み合わせて、分析の幅を広げられること。これがJMPのPython連携の最大のメリットです。
今では、生成AIにやりたいことをプロンプトで伝えるだけで、Pythonのコードを書いてもらえます。そうして生成されたコードをJMPの枠組みで活用するためのヒントとして、本シリーズがお役に立てば幸いです。
最後に、本ブログシリーズ(全4回)の内容を12分程度にまとめた動画を共有いたします(日本語)。
by 増川 直裕(JMP Japan)
Naohiro Masukawa - JMP User Community
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.