クラスタリング手法の可視化
クラスタリング可視化
エディターの注:エヴィー・ファウラーはODSCウエストのスピーカーです。彼女のトーク「顧客セグメンテーションにおける解釈性のギャップを埋める」もぜひチェックしてください!
この秋のOpen Data Science Conferenceでは、クラスタリングモデルの解釈に系統的なアプローチを取る方法について話します。その準備として、クラスタリングモデルのデータ可視化について話しましょう。
ワークスペースの準備
これらの可視化は、データ操作の基本ツール(pandasとnumpy)と可視化の基礎(matplotlibとseaborn)を使用して作成することができます。
from matplotlib import colormaps, pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import load_diabetes
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import pandas as pd
import seaborn as sns
このチュートリアルでは、matplotlibに組み込まれた糖尿病予測データセットを使用します。ODSCでは、効果的なクラスタリングモデルのトレーニングと評価方法についてさらに詳しく説明しますが、今のところはいくつかの単純なk-meansモデルに適合させるだけです。
# 糖尿病データをロード
diabetesData = load_diabetes(as_frame = True).data
# クラスタリング可能な特徴量を中心化およびスケーリング
diabetesScaler = MinMaxScaler().fit(diabetesData)
diabetesDataScaled = pd.DataFrame(diabetesScaler.transform(diabetesData)
, columns = diabetesData.columns
, index = diabetesData.index)
# 3つの小規模なクラスタリングモデルを構築する
km3 = KMeans(n_clusters = 3).fit(diabetesDataScaled)
km4 = KMeans(n_clusters = 4).fit(diabetesDataScaled)
km10 = KMeans(n_clusters = 10).fit(diabetesDataScaled)
カラースキームの選択
matplotlibパッケージは、カラースキームの数々をcolormapsレジストリを通じて提供しています。可視化全体で1つのカラーマップを選ぶことは便利ですが、注意深く選ぶことが重要です。データを低から高までのスケールで解釈できる場合は、連続的な(sequential)マップを選ぶことが適切です。データが2つの極端のいずれかで最も関連性がある場合は、発散的(divergent)マップを選ぶことが重要です。また、対象にテーマに応じたマップを選ぶことも重要です(地形プロジェクトの場合は緑や茶色)。データとその順序の間に特に関係がない場合、nipy_spectralカラーマップが良い選択肢です。
# matplotlibからnipy_spectralカラーマップを選択する
nps = colormaps['nipy_spectral']
# カラーマップ全体を表示する
nps
各matplotlibカラーマップは、RGBA形式で色を記述する複数のタプルで構成されています(ただし、[0, 255]ではなく[0, 1]にスケーリングされた成分を使用します)。マップから個々の色にアクセスするには、整数(0から255の間)または浮動小数点数(0から1の間)を使用できます。0に近い数値は、カラーマップの下端の色に対応し、255に近い整数や1.0に近い浮動小数点数は、カラーマップの上端の色に対応します。直感的には、同じ色は整数または255の商として表現される浮動小数点数のいずれかで記述することができます。
# カラーマップから選択した色を表示する
print(nps(51))
#(0.0, 0.0, 0.8667, 1.0)
print(nps(0.2))
#(0.0, 0.0, 0.8667, 1.0)
可視化の作成
散布図
クラスタリングモデルの代表的な可視化方法は、クラスタリングモデルに入力された各特徴量の組み合わせを比較する一連の散布図で、クラスタの割り当ては色で示されます。これを実現するための組み込みのメソッドもありますが、DIYアプローチの方が色のスキームなどの細かい制御が可能です。
def plotScatters(df, model):
""" データフレームの各列に基づいて散布図を作成する。
色を使用してモデルのラベルを示す。
"""
# フィギュアと軸を作成する
plotRows = df.shape[1]
plotCols = df.shape[1]
fig, axes = plt.subplots(
# データフレームの各特徴量に対して1行1列を作成する
plotRows, plotCols
# 視認性のためにフィギュアサイズを拡大する
, figsize = ((plotCols * 3), (plotRows * 3))
)
# サブプロットを繰り返し処理して散布図を作成する
pltindex = 0
for i in np.arange(0, plotRows):
for j in np.arange(0, plotCols):
pltindex += 1
# 現在のサブプロットを特定する
plt.subplot(plotRows, plotCols, pltindex)
plt.scatter(
# データフレームのi番目とj番目の特徴量を比較する
df.iloc[:, j], df.iloc[:, i]
# 整数のクラスタラベルとカラーマップを使用して色を統一する
, c = model.labels_, cmap = nps
# 重なりを減らすために小さなマーカーサイズを選択する
, s = 1)
# サブプロットの最下行にx軸のラベルを付ける
if i == df.shape[1] - 1:
plt.xlabel(df.columns[j])
# サブプロットの最初の列にy軸のラベルを付ける
if j == 0:
plt.ylabel(df.columns[i])
plt.show()
これらのプロットは、特徴のペア間の関係と、それらの特徴とクラスタ割り当ての関係を示すために二重の役割を果たします。
plotScatters(diabetesDataScaled, km3)
分析が進むにつれて、特徴のサブセットに焦点を絞ることが簡単になります。
plotScatters(diabetesDataScaled.iloc[:, 2:7], km4)
バイオリンプロット
各クラスタ内の各特徴の分布をよりよく把握するために、バイオリンプロットを見ることもできます。バイオリンプロットは、クラシックな箱ひげ図の成熟したいところと考えてください。箱ひげ図は分布のいくつかの主要な特性のみを識別しますが、バイオリンプロットは全体の確率密度関数を示すように輪郭付けされます。
def plotViolins(df, model, plotCols = 5):
""" データフレーム内の各特徴のバイオリンプロットを作成します
モデルのラベルをグループ化するために使用します
"""
# プロットグリッドに必要な行数を計算する
plotRows = df.shape[1] // plotCols
while plotRows * plotCols < df.shape[1]:
plotRows += 1
# 図と軸を作成する
fig, axes = plt.subplots(plotRows, plotCols
# 見やすさのために図のサイズを拡大する
, figsize = ((plotCols * 3), (plotRows * 3))
)
# モデルから一意のクラスタラベルを特定する
uniqueLabels = sorted(np.unique(model.labels_))
# 一意のラベルからカスタムサブパレットを作成する
# これにより、次のようなものが返されます
npsTemp = nps([x / max(uniqueLabels) for x in uniqueLabels])
# 入力データフレームに整数のクラスタラベルを追加する
df2 = df.assign(cluster = model.labels_)
# バイオリンプロットを作成するためにサブプロットを反復処理する
pltindex = 0
for col in df.columns:
pltindex += 1
plt.subplot(plotRows, plotCols, pltindex)
sns.violinplot(
data = df2
# クラスタラベルをxグルーパとして使用する
, x = 'cluster'
# 現在の特徴をy値として使用する
, y = col
# クラスタラベルとカスタムパレットを使用して色の選択を統一する
, hue = model.labels_
, palette = npsTemp
).legend_.remove()
# y軸に特徴名をラベル付けする
plt.ylabel(col)
plt.show()
plotViolins(diabetesDataScaled, km3, plotCols = 5)
ヒストグラム
バイオリンプロットは、各クラスタ内の各特徴の分布を示しますが、各クラスタが各特徴の広範な分布にどのように表れるかを見ることも役立ちます。修正されたヒストグラムはこれをうまく示すことができます。
def histogramByCluster(df, labels, plotCols = 5, nbins = 30, legend = False, vlines = False):
""" 各特徴のヒストグラムを作成します
モデルのラベルを使用して色分けします
"""
# プロットグリッドに必要な行数を計算する
plotRows = df.shape[1] // plotCols
while plotRows * plotCols < df.shape[1]:
plotRows += 1
# 一意のクラスタラベルを特定する
uniqueLabels = sorted(np.unique(labels))
# 図と軸を作成する
fig, axes = plt.subplots(plotRows, plotCols
# 見やすさのために図のサイズを拡大する
, figsize = ((plotCols * 3), (plotRows * 3))
)
pltindex = 0
# 入力データの特徴をループ処理する
for col in df.columns:
# 指定されたビン数で特徴を離散化する
tempBins = np.trunc(nbins * df[col]) / nbins
# 離散化された特徴とクラスタラベルをクロス集計する
tempComb = pd.crosstab(tempBins, labels)
# クロスタブと同じサイズのインデックスを作成する
# これは整列に役立ちます
ind = np.arange(tempComb.shape[0])
# 関連するサブプロットを特定する
pltindex += 1
plt.subplot(plotRows, plotCols, pltindex)
# グループ化されたヒストグラムデータを作成する
histPrep = {}
# 1つのクラスタずつ処理する
for lbl in uniqueLabels:
histPrep.update(
{
# クラスタラベルを関連付ける...
lbl:
# ... バーチャートで
plt.bar(
# 特徴固有のインデックスをx位置として使用する
x = ind
# このクラスタに関連するカウントをバーの高さとして使用する
, height = tempComb[lbl]
# 以前のクラスタバーの上にこのバーを積み重ねる
, bottom = tempComb[[x for x in uniqueLabels if x < lbl]].sum(axis = 1)
# バー間の間隔をなくす
, width = 1
, color = nps(lbl / max(uniqueLabels))
)
}
)
# 特徴名を各プロットのx軸に使用する
plt.xlabel(col)
# 最初の列のプロットのy軸にラベルを付ける
if pltindex % plotCols == 1:
plt.ylabel('頻度')
plt.xticks(ind[0::5], np.round(tempComb.index[0::5], 2))
# 必要に応じて垂直線を重ねる
if vlines:
for vline in vlines:
plt.axvline(x = vline * ind[-1], lw = 0.5, color = 'red')
if legend:
leg1 = []; leg2 = []
for key in histPrep:
leg1 += [histPrep[key]]
leg2 += [str(key)]
plt.legend(leg1, leg2)
plt.show()
histogramByCluster(diabetesDataScaled, km4.labels_)
このプロセスは、クラスタのカテゴリが増えた場合に簡単にスケーリングできます。
histogramByCluster(diabetesDataScaled, km10.labels_)
結論
これらの可視化は、クラスタリングモデルの評価に強力な基盤を提供します。システマティックに行う方法については、ぜひこの秋のサンフランシスコで開催されるOpen Data Science Conferenceでの私の講演に参加してください!
著者について:
Evie Fowlerは、ペンシルベニア州ピッツバーグを拠点とするデータサイエンティストです。現在、彼女は医療部門で働き、患者ケア体験に焦点を当てた予測モデルを開発するデータサイエンティストチームをリードしています。彼女は、予測分析の倫理的な応用や質的手法がデータサイエンスの業務にどのように役立つかに特に興味を持っています。彼女はブラウン大学で学士号を、カーネギーメロン大学で修士号を取得しています。
We will continue to update VoAGI; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles