
在剛接觸機器學習時,會學習到模型是使用一組特徵X和標籤Y來訓練的,例如:使用房子的坪數、屋齡、地段等特徵可以預測這間房子的房價,這就是機器學習中迴歸分析的經典應用。但是在現實場景中,往往會出現數量龐大但是沒有明確標籤或類別的資料,這時應該怎麼利用這些資料,才能挖掘出潛藏在資料中的訊息?
分群任務透過分析資料的特徵與相似性,無需標籤便能將資料中的樣本自動劃分到不同的群體中。如果把資料比作一片無人探索的地圖,那分群就像是透過地形特徵來劃分出不同區域的過程。它不僅能幫助我們理解資料的結構,還能為後續的數據探索、應用建模以及商業決策提供重要的基石。📂 什麼是分群?
分群任務是一種常見的無監督學習(Unsupervised Learning)方法,其目的是在不依賴標籤(Labels)的情況下,根據資料的特徵相似性,將樣本分組成不同的群體(Clusters)。換句話說,分群任務的目標是找到資料中潛在的結構性模式或分組,而不是預測某個具體的標籤。
舉個例子,假如我們有一批商品的資料,包括價格、銷量、類型等資訊,分群後可能會發現商品可以被自動分為三類:高端商品、中端商品和低端商品。這些結果既幫助商家理解市場,也為目標客群的行銷提供指導方向。
📋 基本概念
在分群任務中,我們的目標是將資料點分配到一個或多個群體中,而每個群體應該具有以下特性:
- 群內相似性高:群體內的資料點應該彼此非常相似,表示特徵共享較高。
- 群間相似性低:不同群體之間應該彼此差異明顯,以確保分群具有意義。
分群任務不需要預先知道分群的類別標籤,而是基於資料本身的特徵進行市探(Exploration)或分析,適合於以下場景:
- 探索性分析:如發掘隱藏的群體結構。
- 數據預處理:如移除噪音,或進一步進行特徵提取。
🛠️ 常見應用
消費者分群:
根據消費者的行為特徵(如消費金額、購物頻率)進行分群,幫助企業制定精準的行銷策略,例如:
- 高價值客戶 vs 普通客戶 vs 潛在客戶
醫療領域:
根據病患的臨床數據進行分群,用於探索疾病類型或症狀模式,例如:
- 根據基因表現分群,找到不同的基因型群體
- 藉由分群症狀資料,協助醫生識別罕見疾病
圖像處理:
在電腦視覺中,分群算法用於圖像分割或目標檢測,例如:
- 將圖像的像素分群,以區分背景和前景
文件和文本分析:
在自然語言處理中,分群算法用於文件分組、語義分析,例如:
- 根據文本特徵將文章分組(科技類、商業類、娛樂類)
社交網路分析:
分析社交網路的用戶特徵,以發現群體結構,例如:
- 找出興趣相近的用戶。
- 識別社交網絡中孤立的集群。
🧾 0. 環境建議與可重現性
在環境中安裝所需套件:
pip install numpy pandas scikit-learn matplotlib seaborn joblib
設定亂數種子:
RANDOM_STATE = 42
📦 1. 資料集說明(Dataset Card)
- 名稱:Wine Dataset
- 來源:
sklearn.datasets.load_wine() - 任務:無監督學習(分群分析)
- 樣本數:178
- 特徵數:13 個連續化學成分特徵
- 原始標籤:3 個葡萄酒品種(僅作分析比對,不用於訓練)
🔎 2. 載入與初探(Loading & Quick EDA)
分群任務由於沒有實際的標籤可以跟預測結果比對,非常仰賴視覺化的呈現,利於查看當前的模型分群效果如何,因此整個分群分析的過程中會有大量的視覺化輔助。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_wine
data = load_wine()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = pd.Series(data.target, name="wine_class")
print(X.shape)
print(X.head(3))
print(X.describe())
print("Missing:", X.isna().sum().sum())
sns.pairplot(X.iloc[:, :4]) # 先看前4個特徵的散佈
plt.show()
(178, 13)
alcohol malic_acid ash alcalinity_of_ash magnesium total_phenols \
0 14.23 1.71 2.43 15.6 127.0 2.80
1 13.20 1.78 2.14 11.2 100.0 2.65
2 13.16 2.36 2.67 18.6 101.0 2.80
flavanoids nonflavanoid_phenols proanthocyanins color_intensity hue \
0 3.06 0.28 2.29 5.64 1.04
1 2.76 0.26 1.28 4.38 1.05
2 3.24 0.30 2.81 5.68 1.03
od280/od315_of_diluted_wines proline
0 3.92 1065.0
1 3.40 1050.0
2 3.17 1185.0
alcohol malic_acid ash alcalinity_of_ash magnesium \
count 178.000000 178.000000 178.000000 178.000000 178.000000
mean 13.000618 2.336348 2.366517 19.494944 99.741573
std 0.811827 1.117146 0.274344 3.339564 14.282484
min 11.030000 0.740000 1.360000 10.600000 70.000000
25% 12.362500 1.602500 2.210000 17.200000 88.000000
50% 13.050000 1.865000 2.360000 19.500000 98.000000
75% 13.677500 3.082500 2.557500 21.500000 107.000000
max 14.830000 5.800000 3.230000 30.000000 162.000000
total_phenols flavanoids nonflavanoid_phenols proanthocyanins \
count 178.000000 178.000000 178.000000 178.000000
mean 2.295112 2.029270 0.361854 1.590899
std 0.625851 0.998859 0.124453 0.572359
min 0.980000 0.340000 0.130000 0.410000
25% 1.742500 1.205000 0.270000 1.250000
50% 2.355000 2.135000 0.340000 1.555000
75% 2.800000 2.875000 0.437500 1.950000
max 3.880000 5.080000 0.660000 3.580000
color_intensity hue od280/od315_of_diluted_wines proline
count 178.000000 178.000000 178.000000 178.000000
mean 5.058090 0.957449 2.611685 746.893258
std 2.318286 0.228572 0.709990 314.907474
min 1.280000 0.480000 1.270000 278.000000
25% 3.220000 0.782500 1.937500 500.500000
50% 4.690000 0.965000 2.780000 673.500000
75% 6.200000 1.120000 3.170000 985.000000
max 13.000000 1.710000 4.000000 1680.000000
Missing: 0

🧼 3. 資料前處理(Preprocessing)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
📉 4. 降維與可視化(Dimensionality Reduction & Visualization)
- PCA可以用於降低維度,減少複雜度,詳細內容會在之後的筆記中說明
- 以這張圖來看,可初步判斷這些資料分為三個群體
- 整體資料呈現"U"字型的分布,表示可能存在某種潛在模式
- 其他常用降維方法: t-SNE、UMAP
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
plt.scatter(X_pca[:, 0], X_pca[:, 1], alpha=0.6)
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("PCA 2D Projection (Unlabeled)")
plt.show()

🧠 5. 分群模型訓練(Clustering)
分群任務中,通常需要自己設定要分成幾群,這邊將其設為3群 再將模型的分群結果當做標籤化在PCA的圖上。
- Kmeans是最基本的分群模型
- 其他常用模型: DBSCAN、Agglomerative Clustering、GMM、OPTICS
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, random_state=RANDOM_STATE, n_init=10)
kmeans.fit(X_scaled)
labels = kmeans.labels_
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels, cmap='viridis', alpha=0.7)
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.title("K-Means Clustering Result (k=3)")
plt.show()

📏 6. 模型評估(Clustering Evaluation)
由於分群任務沒有標籤,因此模型評估的方式不是將預測值跟實際值做比較,而是透過計算"組間差異"、"組內差異"和"密度"等來衡量分群的效果。 簡單的說,就是希望各分群之間差異越大越好,各分群自己內部的差異越小越好。
from sklearn.metrics import silhouette_score, davies_bouldin_score
print("Silhouette Score:", silhouette_score(X_scaled, labels))
print("Davies-Bouldin Score:", davies_bouldin_score(X_scaled, labels))
Silhouette Score: 0.2848589191898987
Davies-Bouldin Score: 1.3891879777181646
🧪 7. 不同 k 值實驗(Elbow & Silhouette Method)
分群任務的一個重點就是分群數量(k值)的選擇,因此會透過各種方式來挑選最佳的k值。
- Elbow方法會挑選折線圖轉折的點
- Silhouette方法則是挑選最大值的點
- 從這兩個方法都可以看出k值=3是不錯的選擇
inertia = []
sil_scores = []
ks = range(2, 10)
for k in ks:
km = KMeans(n_clusters=k, random_state=RANDOM_STATE, n_init=10).fit(X_scaled)
inertia.append(km.inertia_)
sil_scores.append(silhouette_score(X_scaled, km.labels_))
plt.plot(ks, inertia, marker='o')
plt.xlabel("k")
plt.ylabel("Inertia")
plt.title("Elbow Method")
plt.show()
plt.plot(ks, sil_scores, marker='o')
plt.xlabel("k")
plt.ylabel("Silhouette Score")
plt.title("Silhouette Score vs k")
plt.show()


💾 8. 模型推論與保存(Inference & Saving Model)
import joblib
# 保存模型
joblib.dump(kmeans, "wine_kmeans_model.joblib")
joblib.dump(scaler, "wine_scaler.joblib")
# 載入模型
kmeans_loaded = joblib.load("wine_kmeans_model.joblib")
scaler_loaded = joblib.load("wine_scaler.joblib")
# 模型推論
new_samples = X.iloc[:5] # 假設取前5筆資料作推論
new_scaled = scaler_loaded.transform(new_samples)
pred_clusters = kmeans_loaded.predict(new_scaled)
print("Predicted clusters for new samples:", pred_clusters)


