k-means必须用欧氏距离,因其目标函数最小化平方欧氏距离和,质心更新依赖向量算术平均,该操作仅在欧氏空间有几何意义;改用余弦相似度会破坏收敛性与物理含义。

余弦相似度在聚类中不直接替代欧氏距离,它通常不用于标准 K-means 聚类;强行替换会导致聚类失效。
为什么 K-means 必须用欧氏距离
K-means 的目标函数(WCSS)最小化的是每个点到其簇中心的 euclidean_distances 平方和。它的更新逻辑依赖于向量差的均值:新质心 = 该簇所有点的坐标算术平均值。这个操作只有在欧氏空间下才保证收敛、有意义。
如果把距离换成余弦相似度,就破坏了算法的数学基础——质心不再代表“几何中心”,mean() 失去几何解释,迭代可能发散或陷入无意义局部解。
- 你不能直接把
cosine_similarity塞进KMeans.fit()—— scikit-learn 的KMeans不支持自定义距离 - 即使手动实现“余弦版 K-means”,每次更新质心时需对向量做
L2归一化再求均值,再重新归一化,否则方向信息被长度污染 - 实践中,用余弦做聚类,更稳妥的做法是先对原始向量做
normalize(X, norm='l2'),再用标准 K-means(此时欧氏距离 ≈ 余弦距离)
什么时候真该用余弦相似度做聚类
当你处理的是**方向敏感、长度无关**的高维稀疏数据,且聚类目标是“语义/主题一致性”而非“数值邻近性”时。典型场景包括:
- TF-IDF 向量聚类新闻文档(长文 vs 短摘要,词频绝对值差异大)
- 用户行为向量(如商品点击频次),关注“偏好分布模式”而非“活跃度高低”
- 嵌入向量(如 sentence-transformers 输出),本身已归一化,
cosine_similarity和euclidean_distances单调等价
这时推荐换用支持余弦距离的聚类器:AgglomerativeClustering 配 metric='cosine',或 DBSCAN 配 metric='precomputed'(先算好余弦距离矩阵)。
常见错误:混淆相似度与距离、忽略归一化
直接拿原始 TF-IDF 矩阵计算 cosine_similarity 得到的是 [0,1] 区间值,但 AgglomerativeClustering 需要的是距离(越小越近)。必须传 1 - cosine_similarity(X),否则会把最相似的样本当成最远的来合并。
- 错误写法:
model.fit(cosine_similarity(X))→ 把相似度当距离用 - 正确写法:
dist_matrix = 1 - cosine_similarity(X); model.fit(dist_matrix) - 更安全做法:用
sklearn.metrics.pairwise_distances(X, metric='cosine'),它直接返回距离矩阵 - 注意:
pairwise_distances对稀疏矩阵支持更好,而cosine_similarity返回密集矩阵,容易爆内存
真正关键的不是“选哪个”,而是明确聚类目标:你要分的是“数值上接近的人”,还是“兴趣方向一致的人”。前者靠欧氏距离,后者靠余弦——但别指望一个 K-means 对象自动切换模式。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











