メインコンテンツへスキップ
ブログ一覧に戻る
統計・データサイエンス

クラスター分析|手法選択・標準化・評価を最短整理(実務ガイド)

2025年10月29日
最終更新: 2026年10月8日
14分で読めます

この記事でわかること

クラスター分析の手法選択、標準化と距離、クラスタ数の比較、安定性の確かめ方を解説します。K-means・階層・GMMの違いを整理し、仮想の商品データをPythonで分類・可視化。シルエット係数が高いことと施策に役立つことを分け、カテゴリ変数、外れ値、新規データ、期間比較での落とし穴まで判断できる実務ガイドです。

商品を二つの群に分けたら、一方は安価でページ数が少なく、もう一方は高価でページ数が多かった。ここから「ライトな読者と熱心な読者に分かれた」と言えるでしょうか。商品の特徴は分かっても、買う人の動機までは測っていません。

クラスター分析は、正解ラベルのない観測を、指定した特徴と似かたに基づいてまとめる方法です。便利なのは、同じ施策で扱っている対象の違いを調べられることです。ただし、群が計算できることと、その群で意思決定を変える価値があることは別です。本記事は顧客・商品の分類を検討する人向けに、設計からPythonの計算、解釈と継続運用までを扱います。

30秒で要点

  • 最初に「1行は何か」「何を似ているとみなすか」「群ごとに何を変えるか」を決める。
  • 標準化は単位による影響を調整する操作。公平性や重要度を自動で決めるものではない。
  • 内部評価、分類の安定性、施策の効果を別々に調べる。きれいな散布図だけで採用しない。

分ける対象と、分けた後の判断を先に書く

似た本を同じ棚へ並べるとき、ページ数で分けるのか、分野で分けるのか、持ち運びやすさで分けるのかで結果は変わります。クラスター分析も、データが勝手に「正しい似かた」を選ぶわけではありません。

観測は表の1行、特徴量は比較に使う列です。同じ顧客の毎日の利用を1行ずつ入れると、利用日数が多い顧客ほど強く影響します。顧客単位の施策なら、同じ観測期間について1顧客1行に集計するなど、目的と行の単位を合わせます。商品分析なら1商品1行なのか、商品と店舗の組み合わせで1行なのかを明記します。

表が収まらない場合は、横にスクロールできます

決めること商品の棚割りを考える仮想例決めないと起きること
対象と期間同じ販売期間に掲載された商品新商品と長期掲載商品のレビュー数を同列に扱う
使用する特徴価格、容量、用途、同期間の販売指標取得できた列を全部入れ、似かたが説明できない
除外・欠測の扱い欠品と販売ゼロ、未評価と低評価を区別記録の欠落だけで一つの群ができる
分類後の判断棚の説明文を変える候補を作る群の名前を付けて分析が終わる
確認する結果探しやすさ、購入率、粗利、返品分かれたことを売上改善と読み替える

これは設計案であり、導入成果の事例ではありません。目的に応じた列選びは必要ですが、目的を先に書けば成功するという保証もありません。収集の偏り、季節性、測定誤差、そもそも明確な群がない可能性も残します。

距離を決めることは、違いの重みを決めること

距離は二つの観測の違いを数値にしたものです。通常のK-meansでは、各列の差を二乗して足すユークリッド距離の二乗を使います。仮に価格差が1,000円、評価差が1点なら、未調整の二乗差の和は1,000,001です。数字の大きい価格差がほぼ全てを占めます。価格を千円単位に直すだけで影響が変わるなら、分類は単位の選択に依存しています。

標準化は出発点であり、重要度の決定ではない

Zスコアによる標準化は、各列から平均を引き、その列の標準偏差で割ります。定数でない列を同じ分散に揃えるので、単位が混在する場合の候補になります。scikit-learnのStandardScalerは学習した平均と標準偏差を保存し、後のデータへ同じ変換を適用します。StandardScaler公式仕様

ただし、測定誤差の大きい列まで同じ尺度で扱うことがあります。価格と価格に強く連動する三つの列を入れると、その性質を重ねて評価することにもなります。「各列を同じ分散にした」と「意味のある特徴を等しく扱った」は同じではありません。

外れ値も確認します。桁違いの値が入力ミスなら修正対象ですが、少数の大型商品なら事業上重要な対象かもしれません。削除や上限への置換を自動で行わず、残した場合と除いた場合で何が変わるかを比較します。中央値や四分位範囲を使うスケーリングを選んでも、その後のK-meansの二乗距離が外れ値に強くなるとは限りません。

カテゴリと欠測を「数字だから」と同列にしない

カテゴリA・B・Cを1・2・3と入力すると、AとCがAとBの2倍離れている扱いになります。その順序に意味がなければ不適切です。ワンホット化は各カテゴリの該当有無を列にしますが、カテゴリ数の多い項目を多数の列に分けたときの重みや、希少なカテゴリを標準化したときの影響を検討します。

数値・名義・順序などが混じるデータには、Gowerの非類似度も候補です。Rのdaisyは列型に応じた差を重み付きで集計し、数値列を範囲で調整します。この距離を選ぶ場合は、対応する階層法などを組み合わせます。通常のK-meansへ距離行列を特徴量として渡すと、別の問題を解くことになります。daisy公式説明

欠測をゼロに置くと、未回答や未掲載の商品を「値が小さい商品」に変えてしまいます。欠測率を列と対象群ごとに確認し、削除、中央値などによる補完、欠測そのもののフラグ化を比較します。補完は失われた真値の回復を保証しません。欠測値補完の公式説明

K-means・階層・GMMは何を仮定しているか

表が収まらない場合は、横にスクロールできます

方法何をまとめるか選ぶ場面主な確認点
K-means各点から最寄りの平均ベクトルへの二乗距離を小さくする数値中心で、まとまりを代表値で説明したいKを指定する。初期値、尺度、細長い形や不均一な密度に注意
階層的クラスタリング小さな群を距離・連結ルールで順に結合するまとまりの段階を樹形図で調べたいWard・平均・完全連結などで構造が変わる。大規模時は費用も確認
GMM複数の正規分布の混合として密度をモデル化する楕円状の広がりや所属の曖昧さを表したい成分数、共分散構造、少数群、初期値、局所解を確認

K-meansの平均ベクトルをセントロイドと呼びます。実在する商品そのものとは限りません。階層法のデンドログラムは結合過程の樹形図で、切る位置によって群の数が変わります。Ward法は群内の二乗偏差を基準にし、ユークリッド距離に対応します。どの距離でも使えるわけではありません。クラスタリング公式ガイド

GMMの「所属確率」は、推定した混合分布モデルの下での値です。「この顧客が真に高級志向である確率」とは言えません。BICなどで成分数を比較できますが、モデルの条件や標本数に依存し、業務上の最適なセグメント数を証明する指標でもありません。Gaussian mixture公式ガイド

曲がった形の群や雑音点を扱う密度ベースの方法もあります。ただし、方法を増やして最もきれいに見える図を選ぶ前に、どの形を「同じ群」としたいかを言葉にします。手法の名前を知ることより、対象の似かたと算法の基準が対応することが大切です。

8商品の仮想データで、群の特徴を確かめる

以下は本に見立てた合成教材です。価格は架空の価格単位、ページ数はページ、design_scoreは便宜的な評価点です。実在商品、購買者の好み、成果を示しません。最初の三つのPythonブロックは、同じノートブックやスクリプトで上から順に実行します。四つ目は単独で実行できます。

2026年10月4日の検算環境はPython 3.12、scikit-learn 1.9.1、NumPy 2.5.3、pandas 3.0.6、SciPy 1.18.1、Matplotlib 3.11.2です。用途別の隔離環境で必要なライブラリを揃えてください。既存システムの依存を一括更新する手順ではありません。

import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

features = ["price", "pages", "design_score"]
df = pd.DataFrame({
    "price": [120,130,90,300,280,310,85,95],
    "pages": [180,200,150,420,410,450,140,155],
    "design_score": [3,4,3,5,5,4,2,3]
})
scaler = StandardScaler()
X = scaler.fit_transform(df[features])
kmeans = KMeans(n_clusters=2, n_init=10, random_state=42)
labels = kmeans.fit_predict(X)
# 分類結果は特徴量とは別の表にする
result = df.assign(cluster=labels)
profile = result.groupby("cluster").agg(
    n=("price", "size"), price=("price", "mean"),
    pages=("pages", "mean"), design_score=("design_score", "mean")
).sort_values("price")
print(profile.round(3).to_string())

価格平均で並べると、低い方は5商品で価格104、ページ165、評価3.000。高い方は3商品で価格296.667、ページ426.667、評価4.667です。分母はそれぞれの群の商品数であり、顧客数ではありません。クラスタ番号0と1は単なる識別子なので、別の実行条件で入れ替わっても意味は変わりません。KMeans公式仕様

このデータだけなら「高価格・多ページの商品群」と説明できます。「高級志向の顧客」「濃い読者向け」といった名前は、まだ測っていない意味を足しています。まず元の単位で表を読み、群の大きさと群内のばらつきも確認します。

二次元の図と、計算に使った距離を区別する

PCAは多くの列を少ない軸へ投影する方法です。ここでは三つの標準化特徴で分類した後、図にするため二つの軸へ写します。分類を二次元上でやり直しているわけではありません。

import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

pca2 = PCA(n_components=2, svd_solver="full")
Z = pca2.fit_transform(X)
fig, ax = plt.subplots(figsize=(6, 5))
for label in sorted(set(labels)):
    idx = labels == label
    ax.scatter(Z[idx, 0], Z[idx, 1], label=f"cluster {label}")
for i, (x, y) in enumerate(Z, start=1):
    ax.annotate(str(i), (x, y), xytext=(4, 4), textcoords="offset points")
ax.set(xlabel="PC1 score", ylabel="PC2 score", aspect="equal")
ax.legend()
fig.tight_layout()
fig.savefig("cluster-pca.png", dpi=150)
plt.close(fig)
print("Two-PC variance ratio:", round(pca2.explained_variance_ratio_.sum(), 6))

PCAの軸の符号は反転することがあります。図の左右が逆でも、同じ射影なら対象間の距離や保持した分散は変わりません。落とした軸に残る違いもあるため、図での近さだけで同じ商品とは判断しません。PCAの公式仕様

中心の棒グラフは、標準化された単位で読む

import pandas as pd
import matplotlib.pyplot as plt

# 元の特徴3列だけを使う。cluster列を混ぜない
centroid = pd.DataFrame(kmeans.cluster_centers_, columns=features)
ax = centroid.T.plot(kind="bar", figsize=(7, 4))
ax.axhline(0, color="gray", linewidth=1)
ax.set(title="Synthetic cluster centers", ylabel="Standardized feature mean")
ax.figure.tight_layout()
ax.figure.savefig("cluster-centers.png", dpi=150)
plt.close(ax.figure)
print("Center matrix shape:", centroid.shape)

出力は(2, 3)です。棒の1は価格1単位ではなく、標準化に使った平均から標準偏差1個分の位置を表します。標準化後の群平均と元単位の群平均は用途が違うため、両方を保存します。担当者へは「標準化得点が高い」だけでなく「価格平均はいくらか」も示すと判断につながります。

Kの比較は、単一の最高点を探す競争ではない

Kを増やすほど、群内二乗和は最適解では増えません。各点を独立の群にすればゼロにできるため、小さい値だけを理由に細分化するのは不十分です。急に改善が小さくなる位置を見るエルボー法は候補を絞る目安ですが、はっきりした曲がり角がないこともあります。有限回の初期化では局所解の影響も残ります。

シルエット係数では、ある点から同じ群の他の点への平均距離をa、別の各群への平均距離のうち最小をbとし、(b - a) / max(a, b)を求めます。例えばa=2、b=5なら0.6です。全体の係数は各点の値の平均です。大きいほど、その距離に対して群が凝集・分離しています。計算可能なラベル数は2以上、観測数未満です。silhouette_score公式仕様

同じ12商品の合成データで、Kを2〜5に変えます。距離や使用する行を変えずに比べ、群の大きさも出力します。

import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score, adjusted_rand_score

ec = pd.DataFrame({
    "price": [120,130,90,300,280,310,85,95,140,260,270,320],
    "reviews": [40,55,20,300,260,310,15,18,70,220,250,330],
    "rating": [3.9,4.1,3.5,4.7,4.6,4.5,3.2,3.6,4.0,4.6,4.7,4.8]
})
E = StandardScaler().fit_transform(ec)
for k in range(2, 6):
    km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(E)
    print(k, round(silhouette_score(E, km.labels_), 3),
          sorted(np.bincount(km.labels_).tolist()))
# 同じ行で、ラベルの番号だけを置換した場合
print("Label permutation ARI:", adjusted_rand_score([0,0,1,1], [1,1,0,0]))

表が収まらない場合は、横にスクロールできます

K平均シルエット係数群の商品数(小さい順)
20.7686・6
30.7073・3・6
40.5533・3・3・3
50.5111・2・3・3・3
上段は12商品の仮想データのK別シルエット係数を同じ0から1の軸で比較し、K2が0.768。下段は別の8商品教材の2群の価格とページの平均を元単位で示す。内部評価と群の内容を別に確かめる図。
上段は12商品のK比較、下段は8商品の群平均。別々の合成教材であり、同じ標本の二つの評価ではありません。棒は実計算値で、売上や施策効果を表しません。

この例ではK=2が最も高いものの、12商品で探索した内部評価です。新たな商品でも同じ分かれ方が続く証拠ではありません。K=5には1商品だけの群があり、scikit-learnではその点のシルエットを0として平均します。外れた重要商品なのか、細分化しすぎなのかを元の値で調べます。

ほかにCalinski–Harabasz指標は群間と群内の散らばりを比べ、大きい方が良いという基準です。Davies–Bouldin指標は群の広がりと中心間距離を比べ、小さい方を選びます。これらも群の幾何に関する指標です。Gap統計のように参照分布との比較を使う方法もありますが、参照の作り方まで含めて検討する必要があります。いずれも施策の効果測定には代わりません。

再現性・安定性・事業上の有用性は三つの問い

再現性は、同じ入力・実装・設定で結果を再現できるかです。乱数の種を固定し、前処理と特徴の順序、ライブラリ版を保存します。安定性は、妥当な範囲で入力や条件を変えても構造が保たれるかです。固定した一つの乱数で成功しても、こちらは未確認です。

同じ観測に対する二つの分類を比べるなら、ARI(調整ランド指数)が使えます。これは観測のペアが同じ群かどうかを基に比較し、番号が入れ替わっても同じ分割なら1になります。上の例の出力も1です。偶然の一致を調整した一致度であり、分類に「正しい意味」があることは示しません。ARI公式仕様

再標本化では、各回に前処理も含めて学習し直し、共通して含まれる対象の分割や、固定した評価対象への割り当てを比較します。群ごとのJaccard類似度(対象集合の共通部分を和集合で割る値)を使うなら、群の対応付けと同じ対象集合であることを決めます。異なる月の別々の顧客を行番号で対応させるのは不適切です。

期間比較には、基準期間で作った変換と中心を固定し、翌期の構成比や中心までの距離を見る方法があります。一方、翌期にも学習し直して構造変化を見る方法では、軸や群が変わるので前期と直接同一視しません。変化が季節性なのか、商品構成や計測の変更なのかも調べます。

将来の性能を評価する場合、標準化、欠測補完、PCAを評価データまで含めて学習してはいけません。分割してから学習側だけでfitし、評価側はtransformします。交差検証の各分割内でも同じです。単一データの探索的な図は全体で計算できますが、それを将来への予測性能と報告しないことが境目です。前処理とデータ漏洩の公式説明

棚割りへ進むなら、分類と施策の検証を分ける

例えばECで群ごとに訴求文を変える案を考えたとします。群に分類すること、群別に異なる文面を出すこと、購入を増やすことは三つの異なる段階です。ある群の購入率が高くても、もともとの価格や流入経路の違いかもしれません。

担当者と確認したいのは「この群には違う案内が必要か」「商品数と運用工数は見合うか」「分類が曖昧な商品をどう扱うか」です。平均だけでなく分位点や代表商品を見て、境界付近の商品も確認します。新商品を既存中心に割り当てる場合は、全ての中心から遠い商品まで無理に説明できた扱いにしません。

施策効果を調べる際は、対象・割付単位・期間・指標を別に決めます。購入率なら分母を対象訪問者などに固定し、売上だけでなく粗利や返品などの副作用も見ます。この段階で初めて、分類を利用した施策が従来案より有用かを評価できます。

小さく確かめるための三つの練習

  1. 価格を円から千円へ変えたら分類が変わった。 未調整の距離で単位の影響を拾っていないか確認する。標準化前後の比較だけでなく、価格へ与える重みが目的に合うか考える。
  2. K=3と4の指標が僅差だった。 最小群、群内のばらつき、施策の違い、初期値や再標本化の変動を並べる。差が小さければ「決められない」として、まず少ない群で説明できるか検討する。
  3. 翌月はクラスタ番号0の意味が逆になった。 ラベル入れ替えか構造変化かを区別する。同じ対象ならARI、対象が違うなら固定モデルでの構成比や特徴分布を確認する。

最初の検証は、用途に関わる少数の列で、二つか三つの候補を作るところから始められます。使用した行と期間、変換、距離、K、種、群平均、群サイズを一枚に残し、別の担当者が名前を付けずに読んでも違いを説明できるか確かめてください。「分類を採用しない」「追加の列を収集する」も検証の結果です。

軸の要約を詳しく見るなら主成分分析(PCA)、カテゴリ中心の潜在的な分類を検討するなら潜在クラス分析、手法の入口を比較するならデータサイエンス手法ハブへ進めます。

よくある質問(FAQ)