Python scikit-learn 1.3 聚类实战:3种算法对比与欧洲语言数据集应用
Python scikit-learn 1.3 聚类实战:3种算法对比与欧洲语言数据集应用
聚类分析是机器学习中无监督学习的重要分支,它能帮助我们发现数据中隐藏的自然分组。本文将带你用Python的scikit-learn 1.3版本,实战三种主流聚类算法:系统聚类、K-Means和AgglomerativeClustering,并应用于一个有趣的欧洲语言数据集。
1. 环境准备与数据加载
在开始之前,确保你已经安装了以下Python库:
pip install scikit-learn==1.3.0 pandas matplotlib seaborn numpy我们将使用一个特殊的欧洲语言距离矩阵作为示例数据。这个数据集记录了6种欧洲语言(英语、挪威语、德语、法语、西班牙语、意大利语)之间的"距离",这个距离是基于数字1-10的拼写差异计算的。
import numpy as np import pandas as pd from scipy.spatial.distance import squareform # 语言缩写:E(英语), N(挪威语), G(德语), Fr(法语), S(西班牙语), I(意大利语) languages = ['E', 'N', 'G', 'Fr', 'S', 'I'] # 距离矩阵(下三角) dist_matrix = np.array([ [0], # E [2, 0], # N [6, 6, 0], # G [6, 6, 2, 0], # Fr [6, 6, 6, 6, 0], # S [6, 6, 6, 6, 2, 0] # I ]) # 转换为完整的对称距离矩阵 full_dist_matrix = squareform(dist_matrix)2. 三种聚类算法原理与实现
2.1 系统聚类(Hierarchical Clustering)
系统聚类通过连续合并或分裂簇来构建树状图(dendrogram)。scikit-learn中的AgglomerativeClustering实现了这种方法。
核心参数解析:
| 参数 | 说明 | 常用值 |
|---|---|---|
| n_clusters | 最终簇的数量 | 整数 |
| linkage | 链接策略 | 'ward', 'complete', 'average', 'single' |
| affinity | 距离度量 | 'euclidean', 'manhattan', 'cosine', 'precomputed' |
from sklearn.cluster import AgglomerativeClustering import matplotlib.pyplot as plt from scipy.cluster.hierarchy import dendrogram # 系统聚类实现 def plot_dendrogram(model, **kwargs): counts = np.zeros(model.children_.shape[0]) n_samples = len(model.labels_) for i, merge in enumerate(model.children_): current_count = 0 for child_idx in merge: if child_idx < n_samples: current_count += 1 else: current_count += counts[child_idx - n_samples] counts[i] = current_count linkage_matrix = np.column_stack([model.children_, model.distances_, counts]).astype(float) dendrogram(linkage_matrix, **kwargs) model = AgglomerativeClustering(distance_threshold=0, n_clusters=None, affinity='precomputed', linkage='complete') model = model.fit(full_dist_matrix) plt.figure(figsize=(10, 6)) plt.title('欧洲语言谱系聚类图') plot_dendrogram(model, labels=languages, orientation='right') plt.show()2.2 K-Means聚类
K-Means是最著名的动态聚类算法,虽然通常用于欧式空间数据,但我们可以通过多维缩放(MDS)将距离矩阵转换为适合K-Means的形式。
from sklearn.manifold import MDS from sklearn.cluster import KMeans # 将距离矩阵转换为2维坐标 mds = MDS(n_components=2, dissimilarity='precomputed', random_state=42) coordinates = mds.fit_transform(full_dist_matrix) # K-Means聚类 kmeans = KMeans(n_clusters=3, random_state=42) kmeans_labels = kmeans.fit_predict(coordinates) # 可视化 plt.figure(figsize=(8, 6)) plt.scatter(coordinates[:, 0], coordinates[:, 1], c=kmeans_labels, cmap='viridis') for i, lang in enumerate(languages): plt.annotate(lang, (coordinates[i, 0], coordinates[i, 1])) plt.title('K-Means聚类结果') plt.show()2.3 有序约束聚类(AgglomerativeClustering模拟)
虽然scikit-learn没有直接实现有序聚类,但我们可以通过调整AgglomerativeClustering的参数来模拟类似效果。
# 使用AgglomerativeClustering模拟有序约束 ordered_model = AgglomerativeClustering(n_clusters=3, affinity='precomputed', linkage='single') ordered_labels = ordered_model.fit_predict(full_dist_matrix) # 结果展示 result_df = pd.DataFrame({ 'Language': languages, 'SystemCluster': model.labels_, 'KMeans': kmeans_labels, 'OrderedLike': ordered_labels }) print(result_df)3. 算法对比与结果分析
让我们从几个关键维度比较这三种算法:
1. 计算复杂度对比
| 算法 | 时间复杂度 | 空间复杂度 | 适合数据规模 |
|---|---|---|---|
| 系统聚类 | O(n³) | O(n²) | 中小型(n<10000) |
| K-Means | O(nki) | O(n+k) | 大型 |
| 有序约束 | O(n²) | O(n²) | 中小型 |
2. 我们的语言数据集结果
from sklearn.metrics import silhouette_score # 计算轮廓系数(仅适用于K-Means和有序约束) kmeans_score = silhouette_score(coordinates, kmeans_labels) ordered_score = silhouette_score(coordinates, ordered_labels) print(f"K-Means轮廓系数: {kmeans_score:.3f}") print(f"有序约束轮廓系数: {ordered_score:.3f}")3. 实际应用建议
- 当数据有明确的距离/相似性定义时,系统聚类是首选
- 对于大型数据集,K-Means更高效
- 当数据有潜在的顺序关系时,可尝试单链接(single linkage)的层次聚类
4. 高级技巧与优化
4.1 最佳簇数确定
对于K-Means,我们可以使用肘部法则和轮廓分析:
from sklearn.metrics import silhouette_samples # 肘部法则 inertia = [] for k in range(2, 6): kmeans = KMeans(n_clusters=k, random_state=42) kmeans.fit(coordinates) inertia.append(kmeans.inertia_) plt.figure(figsize=(8, 4)) plt.plot(range(2, 6), inertia, 'bo-') plt.xlabel('簇数') plt.ylabel('SSE') plt.title('肘部法则') plt.show()4.2 距离度量选择
当使用层次聚类时,链接策略的选择至关重要:
- 完全链接(complete): 适合发现紧凑的、大小相近的簇
- 单链接(single): 能发现非凸形状的簇,但对噪声敏感
- 平均链接(average): 平衡了上述两种方法的优缺点
4.3 特征工程技巧
对于距离矩阵数据,可以考虑:
- 多维缩放(MDS) - 如我们前面所用
- t-SNE - 更适合可视化
- 等距映射(Isomap) - 保留全局几何结构
from sklearn.manifold import TSNE tsne = TSNE(n_components=2, metric='precomputed', random_state=42) tsne_coords = tsne.fit_transform(full_dist_matrix) plt.figure(figsize=(8, 6)) plt.scatter(tsne_coords[:, 0], tsne_coords[:, 1], c=kmeans_labels, cmap='viridis') for i, lang in enumerate(languages): plt.annotate(lang, (tsne_coords[i, 0], tsne_coords[i, 1])) plt.title('t-SNE可视化') plt.show()在实际项目中,我发现t-SNE虽然能产生漂亮的可视化效果,但随机性较强,不适合直接用于聚类。而MDS虽然计算成本较高,但结果更稳定可靠。
