无监督学习处理没有标签的数据,旨在发现隐藏的数据结构和模式。本文涵盖聚类、降维与关联规则三大方向的核心算法。
1. 聚类 (Clustering)
聚类将相似的数据点分到同一组。关键在于定义"相似性"和"簇的形状"。
1.1 K-Means 聚类
K-Means 最小化簇内平方和 (WCSS):
$$J = \sum_{i=1}^{k}\sum_{x \in C_i}|x - \mu_i|^2$$
算法步骤:
- 随机选择 k 个初始中心点
- 将每个样本分配到最近的中心点所属簇
- 重新计算每个簇的中心点(均值)
- 重复 2-3 直到收敛
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
# 标准化(K-Means 对尺度敏感)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# K-Means
kmeans = KMeans(
n_clusters=4, # 簇数量
init='k-means++', # 智能初始化
n_init=10, # 运行 10 次取最优
max_iter=300,
random_state=42
)
labels = kmeans.fit_predict(X_scaled)
# 簇中心与惯性
centers = kmeans.cluster_centers_
inertia = kmeans.inertia_ # WCSS
# 可视化
import matplotlib.pyplot as plt
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='viridis')
plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='x', s=200)
1.2 肘部法则确定 K 值
inertias = []
K_range = range(1, 11)
for k in K_range:
km = KMeans(n_clusters=k, random_state=42, n_init=10)
km.fit(X_scaled)
inertias.append(km.inertia_)
plt.plot(K_range, inertias, 'bo-')
plt.xlabel('K')
plt.ylabel('WCSS')
plt.title('Elbow Method')
plt.show()
1.3 轮廓系数 (Silhouette Score)
from sklearn.metrics import silhouette_score, silhouette_samples
score = silhouette_score(X_scaled, labels) # [-1, 1],越高越好
sample_scores = silhouette_samples(X_scaled, labels)
1.4 层次聚类 (Hierarchical Clustering)
凝聚式(Agglomerative):从每个样本为一簇开始,逐步合并最近的簇。
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
# 层次聚类
agg = AgglomerativeClustering(
n_clusters=4,
linkage='ward', # 'ward', 'complete', 'average', 'single'
metric='euclidean'
)
labels = agg.fit_predict(X_scaled)
# 绘制树状图
Z = linkage(X_scaled, method='ward')
dendrogram(Z, truncate_mode='lastp', p=20)
plt.title('Hierarchical Clustering Dendrogram')
plt.show()
| 链接方式 | 定义 | 特点 |
|---|---|---|
| Ward | 最小化合并后簇内方差 | 倾向于球形簇 |
| Complete | 两簇最远点距离 | 对异常值敏感 |
| Average | 两簇平均距离 | 平衡 |
| Single | 两簇最近点距离 | 可发现链式簇 |
1.5 DBSCAN:基于密度的聚类
DBSCAN 通过密度连接发现任意形状的簇,自动识别噪声点。
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(
eps=0.5, # 邻域半径
min_samples=5 # 核心点最少邻居数
)
labels = dbscan.fit_predict(X_scaled)
# labels = -1 表示噪声点
n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = list(labels).count(-1)
print(f"发现 {n_clusters} 个簇,{n_noise} 个噪声点")
关键概念:
- 核心点:邻域内样本数 ≥ min_samples
- 边界点:在核心点邻域内但自身不是核心点
- 噪声点:既非核心也非边界
参数选择:通过 k-距离图确定 eps。
from sklearn.neighbors import NearestNeighbors
knn = NearestNeighbors(n_neighbors=5)
knn.fit(X_scaled)
distances, _ = knn.kneighbors(X_scaled)
distances = np.sort(distances[:, 4]) # 第 5 近邻距离
plt.plot(distances)
plt.ylabel('5-NN Distance')
# 拐点处作为 eps
| 算法 | 簇形状 | 需预设簇数 | 处理噪声 | 适用场景 |
|---|---|---|---|---|
| K-Means | 球形 | ✅ | ❌ | 大规模、簇大小均匀 |
| 层次聚类 | 任意 | ✅ | ❌ | 数据量较小、需树状结构 |
| DBSCAN | 任意 | ❌ | ✅ | 发现不规则簇、有噪声 |
| GMM | 椭球形 | ✅ | ❌ | 软聚类、概率归属 |
1.6 高斯混合模型 (GMM)
GMM 假设数据来自有限个高斯分布的叠加,提供软聚类(概率归属)。
from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(
n_components=4,
covariance_type='full', # 'full', 'tied', 'diag', 'spherical'
random_state=42
)
gmm.fit(X_scaled)
labels = gmm.predict(X_scaled)
probs = gmm.predict_proba(X_scaled) # 每个样本属于各簇的概率
# AIC/BIC 选模型
print(f"AIC: {gmm.aic(X_scaled)}, BIC: {gmm.bic(X_scaled)}")
2. 降维 (Dimensionality Reduction)
2.1 主成分分析 PCA
PCA 通过正交变换将相关变量转换为线性不相关的主成分,保留最大方差方向。
数学原理:
- 数据标准化
- 计算协方差矩阵
- 协方差矩阵特征分解
- 取前 k 个最大特征值对应的特征向量
from sklearn.decomposition import PCA
pca = PCA(n_components=0.95) # 保留 95% 方差,或指定整数维度
X_pca = pca.fit_transform(X_scaled)
print(f"原始维度: {X.shape[1]} → 降维后: {X_pca.shape[1]}")
print(f"各主成分方差比例: {pca.explained_variance_ratio_}")
print(f"累计方差比例: {np.cumsum(pca.explained_variance_ratio_)}")
# 可视化方差
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('Components')
plt.ylabel('Cumulative Explained Variance')
plt.axhline(y=0.95, color='r', linestyle='--')
2.2 核 PCA
from sklearn.decomposition import KernelPCA
kpca = KernelPCA(
n_components=2,
kernel='rbf', # 'linear', 'poly', 'rbf', 'sigmoid'
gamma=0.04
)
X_kpca = kpca.fit_transform(X_scaled)
2.3 t-SNE:可视化降维
t-SNE 保留局部邻域结构,适合高维数据可视化。
from sklearn.manifold import TSNE
tsne = TSNE(
n_components=2,
perplexity=30, # 邻居数量,5-50
learning_rate='auto',
n_iter=1000,
random_state=42,
n_jobs=-1
)
X_tsne = tsne.fit_transform(X_scaled)
plt.scatter(X_tsne[:, 0], X_tsne[:, 1], c=y, cmap='tab10')
plt.title('t-SNE Visualization')
注意:
- t-SNE 是随机的,每次结果不同
- 主要用于可视化,不建议用于后续建模(信息有损失,不稳定)
- 大数据集(>10k)先用 PCA 降到 50 维再用 t-SNE
2.4 UMAP:更快速的新选择
import umap
reducer = umap.UMAP(
n_neighbors=15,
min_dist=0.1,
n_components=2,
random_state=42
)
X_umap = reducer.fit_transform(X_scaled)
plt.scatter(X_umap[:, 0], X_umap[:, 1], c=y, cmap='tab10')
UMAP 相比 t-SNE:
- 更快(支持大数据集)
- 更好地保留全局结构
- 支持 transform 新数据点
| 方法 | 原理 | 线性/非线性 | 支持 transform | 适用场景 |
|---|---|---|---|---|
| PCA | 最大方差投影 | 线性 | ✅ | 预处理、特征压缩 |
| LDA | 类间散度最大化 | 线性 | ✅ | 有标签时的降维 |
| t-SNE | 邻域概率分布匹配 | 非线性 | ❌ | 可视化 |
| UMAP | 流形学习 + 拓扑 | 非线性 | ✅ | 可视化 + 特征表示 |
| Autoencoder | 神经网络编码 | 非线性 | ✅ | 深度学习表示 |
3. 异常检测
3.1 基于统计的方法
from sklearn.ensemble import IsolationForest
from sklearn.neighbors import LocalOutlierFactor
# Isolation Forest:通过随机特征分割隔离异常点
iso = IsolationForest(contamination=0.1, random_state=42)
outliers = iso.fit_predict(X_scaled) # -1 为异常,1 为正常
# LOF:局部异常因子
lof = LocalOutlierFactor(n_neighbors=20, contamination=0.1)
outliers = lof.fit_predict(X_scaled)
3.2 基于重建误差
from sklearn.decomposition import PCA
# 用 PCA 重建,异常点重建误差大
pca = PCA(n_components=0.95)
X_pca = pca.fit_transform(X_scaled)
X_reconstructed = pca.inverse_transform(X_pca)
reconstruction_error = np.mean((X_scaled - X_reconstructed)**2, axis=1)
threshold = np.percentile(reconstruction_error, 95)
anomalies = reconstruction_error > threshold
4. 关联规则 (Association Rules)
4.1 Apriori 算法
挖掘"如果购买 A,那么也购买 B"的规则。
三个核心指标:
- 支持度 (Support):$P(A \cup B) = \frac{包含 A 和 B 的交易数}{总交易数}$
- 置信度 (Confidence):$P(B|A) = \frac{P(A \cup B)}{P(A)}$
- 提升度 (Lift):$\frac{P(B|A)}{P(B)}$,>1 表示正相关
from mlxtend.frequent_patterns import apriori, association_rules
from mlxtend.preprocessing import TransactionEncoder
# 交易数据
transactions = [
['牛奶', '面包', '尿布'],
['牛奶', '尿布', '啤酒', '鸡蛋'],
['牛奶', '面包', '尿布', '啤酒'],
['面包', '鸡蛋'],
['面包', '尿布', '啤酒']
]
# 编码为 One-Hot
te = TransactionEncoder()
te_array = te.fit_transform(transactions)
df = pd.DataFrame(te_array, columns=te.columns_)
# 挖掘频繁项集
frequent_itemsets = apriori(df, min_support=0.4, use_colnames=True)
# 生成关联规则
rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=0.7)
print(rules[['antecedents', 'consequents', 'support', 'confidence', 'lift']])
4.2 FP-Growth(更高效)
from mlxtend.frequent_patterns import fpgrowth
frequent_itemsets = fpgrowth(df, min_support=0.4, use_colnames=True)
FP-Growth 用频繁模式树 (FP-Tree) 避免 Apriori 的候选项集生成,速度提升一个数量级。
5. 完整实战:客户分群
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
# 加载客户数据
df = pd.read_csv('customers.csv')
features = ['recency', 'frequency', 'monetary', 'age', 'tenure']
X = df[features]
# 标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# K-Means 分群
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
df['cluster'] = kmeans.fit_predict(X_scaled)
# 簇特征分析
cluster_summary = df.groupby('cluster')[features].mean()
print(cluster_summary)
# PCA 可视化
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=df['cluster'], cmap='Set1')
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.title('Customer Segments')
plt.colorbar(label='Cluster')
# 标签解读
# Cluster 0: 高价值忠诚客户 → VIP 服务
# Cluster 1: 流失风险客户 → 召回策略
# Cluster 2: 新客户 → 引导升级
# Cluster 3: 低频客户 → 促销激活
总结
| 任务 | 推荐算法 | 关键超参数 | 评估指标 |
|---|---|---|---|
| 聚类 (球形) | K-Means | K | 轮廓系数、WCSS |
| 聚类 (任意形状) | DBSCAN | eps, min_samples | 噪声比、簇数 |
| 聚类 (软划分) | GMM | n_components | AIC/BIC |
| 降维 (预处理) | PCA | n_components (方差比) | 重建误差 |
| 降维 (可视化) | t-SNE/UMAP | perplexity/n_neighbors | 视觉解释 |
| 异常检测 | Isolation Forest | contamination | AUC-PR |
| 关联规则 | FP-Growth | min_support, min_confidence | Lift |
无监督学习的评价比监督学习更主观,需要结合业务含义验证聚类结果。建议的验证方法:
- 多个算法对照,看结果是否一致
- 簇内方差小、簇间距离大
- 与业务指标关联(如客户分群的消费差异显著)
- 可视化检查(PCA/t-SNE 投影)
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。