K-meansモデルの構築とラベリング
クラスタリング分析を行う場合、まず対象となる特徴量を抽出し、アルゴリズムのパラメータを定義します。scikit-learnのKMeansクラスを利用すると、効率的にモデルを構築できます。
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# データセットの読み込み
dataset = pd.read_csv("transport_data.csv", encoding="utf-8")
feature_cols = ["num_cities", "num_provinces", "distance_km", "complexity_index"]
X = dataset[feature_cols]
# ハイパーパラメータの設定
cluster_count = 5
kmeans_model = KMeans(
n_clusters=cluster_count,
init="k-means++",
n_init=10,
max_iter=300,
tol=1e-4,
random_state=42
)
# モデルの学習
kmeans_model.fit(X)
# 結果の抽出
assigned_clusters = kmeans_model.labels_
cluster_centroids = kmeans_model.cluster_centers_
# 新規データへの適用予測
predicted_labels = kmeans_model.predict(X)
クラスタリング結果の可視化
学習済みモデルの出力結果を把握するため、特徴量の次元数に応じて2Dまたは3Dプロットを行います。Matplotlibを活用し、データポイントと重心を別カラーで描画します。
plt.rcParams["font.family"] = "MS Gothic"
plt.rcParams["axes.unicode_minus"] = False
palette = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd"]
# 3次元プロット(特徴量が3つ以上の場合)
fig = plt.figure(figsize=(8, 6))
ax_3d = fig.add_subplot(111, projection="3d")
for idx in range(cluster_count):
mask = assigned_clusters == idx
ax_3d.scatter(
dataset.loc[mask, "num_cities"],
dataset.loc[mask, "num_provinces"],
dataset.loc[mask, "distance_km"],
color=palette[idx],
alpha=0.7
)
ax_3d.scatter(
cluster_centroids[:, 0],
cluster_centroids[:, 1],
cluster_centroids[:, 2],
marker="*",
s=200,
color="black",
label="Centroids"
)
ax_3d.set_xlabel("都市数")
ax_3d.set_ylabel("通過省份数")
ax_3d.set_zlabel("総距離(km)")
ax_3d.legend()
plt.show()
# 2次元プロット(例:2つの指標)
fig_2d, ax_2d = plt.subplots()
for i in range(cluster_count):
mask_2d = assigned_clusters == i
ax_2d.scatter(
dataset.loc[mask_2d, "num_provinces"],
dataset.loc[mask_2d, "distance_km"],
color=palette[i]
)
ax_2d.scatter(cluster_centroids[:, 1], cluster_centroids[:, 0],
marker="x", s=150, color="black")
ax_2d.set_xlabel("通過省份数")
ax_2d.set_ylabel("総距離(km)")
plt.show()
最適なクラスタ数の判定指標
K-meansでは事前に入力するクラスタ数(k)によって結果が大きく変動します。客観的な数値指標を用いて適切なk値を決定する手法を紹介します。
肘方法(Elbow Method)
クラスタ数が増加するに伴う Within-Cluster Distance の減少率を観察します。減少率が緩やかになる「曲がり角」を最適なクラスタ数とみなします。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
data_matrix = dataset[feature_cols].values
manhattan_inertias = []
k_range = range(1, 10)
for n in k_range:
model_tmp = KMeans(n_clusters=n, random_state=42)
model_tmp.fit(data_matrix)
cluster_dist_sum = 0.0
for cluster_id in range(n):
pts_in_cluster = data_matrix[model_tmp.labels_ == cluster_id]
center = model_tmp.cluster_centers_[cluster_id]
# ベクトル演算によるマンハッタン距離の集計
cluster_dist_sum += np.sum(np.abs(pts_in_cluster - center))
manhattan_inertias.append(cluster_dist_sum)
plt.figure()
plt.plot(k_range, manhattan_inertias, marker="o", linestyle="--")
plt.xlabel("クラスタ数 k")
plt.ylabel("マンハッタン距離の総和")
plt.grid(True)
plt.show()
輪郭係数(Silhouette Score)
各データポイントが自身のクラスタ内でどの程度密に集まり、他のクラスタとどの程度離れているかを-1~1の範囲で評価します。値が高いほど分離性能が良いと判断できます。
from sklearn.metrics import silhouette_score
silhouette_values = []
eval_range = range(2, 10)
for k_val in eval_range:
clf = KMeans(n_clusters=k_val, n_init=10, random_state=42)
clf.fit(data_matrix)
score = silhouette_score(data_matrix, clf.labels_)
silhouette_values.append(score)
plt.figure()
plt.plot(eval_range, silhouette_values, marker="s", color="#2ca02c")
plt.xlabel("クラスタ数 k")
plt.ylabel("輪郭係数")
plt.title("クラスタ数に対する分離度評価")
plt.grid(True)
plt.show()