【K-Means深度探索(五)】不止欧氏距离:K-Means中距离度量那些事儿


文章目录


引言:K-Means的"心灵之窗"------距离度量

亲爱的读者朋友们,欢迎回到我们的"K-Means深度探索"系列!在前几篇文章中,我们从零手撕了 K-Means 算法的核心,学会了 K 值选择、K-Means++ 初始化优化,以及 MiniBatch K-Means 在大数据场景下的应用。你已经掌握了 K-Means 的"骨架"和"肌肉"!

然而,K-Means 算法之所以能够"物以类聚",其核心就在于它能衡量数据点之间的"相似性"或"不相似性"。而这种相似性,正是通过**距离度量(Distance Metric)**来定义的。当我们说"某个数据点离质心最近"时,这个"最近"就是由我们选择的距离度量标准来判定的。

在之前的实践中,我们默认使用的都是最常见的欧氏距离(Euclidean Distance)。它直观、易懂,但在真实世界中,数据往往复杂多变,欧氏距离并非总是最佳选择。不同的数据类型、不同的业务场景,可能需要 K-Means 戴上不同的"心灵之窗",才能准确地识别数据点之间的真实关系。

今天,我们就来一场"距离度量"的深度之旅,探索除了欧氏距离之外,还有哪些强大的距离度量方式,它们各自的特点、适用场景,以及它们如何影响你的 K-Means 聚类结果。准备好了吗?让我们一起拓宽 K-Means 的"视野"!

欧氏距离:最常见的"直线距离"

理论回顾

欧氏距离,也被称为 L2 范数,是我们日常生活中最直观的距离概念------两点之间直线最短。在二维或三维空间中,它就是两点之间线段的长度。

对于两个 n n n 维向量 x = ( x 1 , x 2 , . . . , x n ) x = (x_1, x_2, ..., x_n) x=(x1,x2,...,xn) 和 y = ( y 1 , y 2 , . . . , y n ) y = (y_1, y_2, ..., y_n) y=(y1,y2,...,yn),欧氏距离计算公式为:
d ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 d(x, y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2} d(x,y)=∑i=1n(xi−yi)2

适用场景与特点
  • 适用: 数据特征具有连续性、数值型且在几何空间中具有实际意义的场景,例如地理坐标、物理测量值等。它倾向于形成球形或椭球形的簇。

  • 优点: 直观、易于理解和计算。

  • 缺点:

    • 对量纲敏感: 如果不同特征的取值范围差异很大,量纲大的特征会主导距离计算,因此**特征缩放(Feature Scaling)**在应用欧氏距离前至关重要。
    • 对异常值敏感: 距离是平方和的形式,异常值会对距离产生较大影响。
    • "维度灾难": 在高维空间中,所有点之间的距离会趋于相等,欧氏距离的区分能力会下降。

曼哈顿距离:街区中的"出租车距离"

理论解读

曼哈顿距离,又称 L1 范数或"城市街区距离"(Taxicab Distance),指的是在网格状的城市中,从一个交叉口到另一个交叉口,只能沿着街道(平行于坐标轴)行走的距离。

对于两个 n n n 维向量 x x x 和 y y y,曼哈顿距离计算公式为:
d ( x , y ) = ∑ i = 1 n ∣ x i − y i ∣ d(x, y) = \sum_{i=1}^{n} |x_i - y_i| d(x,y)=∑i=1n∣xi−yi∣

适用场景与特点
  • 适用:

    • 当特征维度较高时,曼哈顿距离在高维空间中的表现可能比欧氏距离更稳定。
    • 当数据存在较多离群点时,由于曼哈顿距离使用绝对值而不是平方,它对异常值的敏感度相对较低。
    • 当特征表示不同"类型"的成本或差异,并且这些成本是线性累加时,曼哈顿距离可能更合适。例如,评估两个房屋在"卧室数量差异"和"卫生间数量差异"上的总和。
  • 优点: 相对欧氏距离,对异常值不那么敏感;在高维空间中,其区分度可能更好。

  • 缺点: 在某些几何直观的场景中,可能不如欧氏距离符合人类的直觉。

其他距离度量(简要提及)

除了欧氏距离和曼哈顿距离,还有许多其他的距离度量方式,它们根据数据的不同特性而设计:

  • 闵可夫斯基距离 (Minkowski Distance): 它是欧氏距离和曼哈顿距离的泛化。
    d ( x , y ) = ( ∑ i = 1 n ∣ x i − y i ∣ p ) 1 / p d(x, y) = (\sum_{i=1}^{n} |x_i - y_i|^p)^{1/p} d(x,y)=(∑i=1n∣xi−yi∣p)1/p

    当 p = 1 p=1 p=1 时是曼哈顿距离,当 p = 2 p=2 p=2 时是欧氏距离。

  • 余弦相似度 (Cosine Similarity) / 余弦距离:

    • 适用: 主要用于衡量两个向量在方向上的相似性,而非绝对值大小。在文本挖掘(文档相似度)、推荐系统(用户偏好相似度)等高维稀疏数据场景中非常有效。
    • 原理: 计算两个向量夹角的余弦值。余弦值越接近 1,表示夹角越小,方向越相似。
    • 余弦距离 = 1 - 余弦相似度
  • 汉明距离 (Hamming Distance):

    • 适用: 用于比较两个等长字符串或二进制向量之间不同位的数量。
    • 原理: 统计两个二进制串中对应位置不同的位数。

手把手代码实践:度量不同,感受各异

sklearn.cluster.KMeans 默认且只支持欧氏距离来计算点到质心的距离并更新质心。这是因为 K-Means 的质心更新(求均值)在数学上是最小化欧氏距离的平方和的,这种匹配性使得算法在理论上非常优雅。

如果我们需要使用其他距离度量(如曼哈顿距离)来运行 K-Means 风格的聚类,通常需要自己实现 K-Means 的迭代过程 ,或者使用支持自定义距离度量的其他聚类算法(例如 sklearn.cluster.AgglomerativeClustering 可以通过 metric 参数指定多种距离)。

为了让大家直观感受不同距离度量的差异,我们来写一个简单的函数,计算这两个距离,并观察它们在同一组点上的结果。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import euclidean, cityblock # 从scipy导入欧氏和曼哈顿距离

# 1. 模拟数据点
# 两个点在二维空间中
point_a = np.array([1, 1])
point_b = np.array([4, 5])
point_c = np.array([2, 4]) # 引入第三个点用于比较

# 2. 手动实现欧氏距离和曼哈顿距离函数(为了加深理解,与scipy对比)
def custom_euclidean_distance(p1, p2):
    return np.sqrt(np.sum((p1 - p2)**2))

def custom_manhattan_distance(p1, p2):
    return np.sum(np.abs(p1 - p2))

# 3. 计算并对比距离
print(f"点 A: {point_a}, 点 B: {point_b}, 点 C: {point_c}")

# A 到 B 的距离
dist_ab_euclidean = custom_euclidean_distance(point_a, point_b)
dist_ab_manhattan = custom_manhattan_distance(point_a, point_b)
print(f"\n点 A 到点 B 的欧氏距离: {dist_ab_euclidean:.2f}")
print(f"点 A 到点 B 的曼哈顿距离: {dist_ab_manhattan:.2f}") # (4-1) + (5-1) = 3 + 4 = 7

# A 到 C 的距离
dist_ac_euclidean = custom_euclidean_distance(point_a, point_c)
dist_ac_manhattan = custom_manhattan_distance(point_a, point_c)
print(f"\n点 A 到点 C 的欧氏距离: {dist_ac_euclidean:.2f}")
print(f"点 A 到点 C 的曼哈顿距离: {dist_ac_manhattan:.2f}") # (2-1) + (4-1) = 1 + 3 = 4

# B 到 C 的距离
dist_bc_euclidean = custom_euclidean_distance(point_b, point_c)
dist_bc_manhattan = custom_manhattan_distance(point_b, point_c)
print(f"\n点 B 到点 C 的欧氏距离: {dist_bc_euclidean:.2f}")
print(f"点 B 到点 C 的曼哈顿距离: {dist_bc_manhattan:.2f}") # (4-2) + (5-4) = 2 + 1 = 3

# 使用 scipy 验证 (仅作为参考,实际手撕KMeans时会用numpy实现)
print("\n--- Scipy 验证 ---")
print(f"Scipy 欧氏距离 (A到B): {euclidean(point_a, point_b):.2f}")
print(f"Scipy 曼哈顿距离 (A到B): {cityblock(point_a, point_b):.2f}")


# 4. 可视化直观理解
plt.figure(figsize=(8, 6))
plt.plot([point_a[0], point_b[0]], [point_a[1], point_b[1]], 'k--', alpha=0.6, label='欧氏距离路径') # 欧氏距离是直线
plt.plot([point_a[0], point_b[0]], [point_a[1], point_a[1]], 'r:', alpha=0.6) # 曼哈顿距离横向路径
plt.plot([point_b[0], point_b[0]], [point_a[1], point_b[1]], 'r:', alpha=0.6, label='曼哈顿距离路径') # 曼哈顿距离纵向路径

plt.scatter(point_a[0], point_a[1], s=100, color='blue', label='点 A')
plt.scatter(point_b[0], point_b[1], s=100, color='green', label='点 B')
plt.scatter(point_c[0], point_c[1], s=100, color='purple', label='点 C')

plt.xlim(0, 6)
plt.ylim(0, 6)
plt.title('欧氏距离与曼哈顿距离的几何对比')
plt.xlabel('X轴')
plt.ylabel('Y轴')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend()
plt.show()

从输出结果和图表中可以看到,欧氏距离和曼哈顿距离对于同一对点,其计算结果是不同的,并且几何含义也不同。在我们的例子中,AC 的曼哈顿距离(4.00)比 AB 的曼哈顿距离(7.00)小得多,这可能意味着在曼哈顿距离的视角下,C 更接近 A。而欧氏距离也呈现出类似的趋势,但具体数值和相对大小可能不同。

实践的深度思考:

  • 选择的艺术: 没有"万能"的距离度量。正确的选择取决于你对数据本质的理解,以及你希望 K-Means 找到什么类型的"相似性"。

    • 如果簇是大致球形且特征数值意义明确, 欧氏距离通常是首选。
    • 如果数据点有很多离群值,或者特征维度非常高,且希望减少极端值影响, 曼哈顿距离可能更合适。
    • 如果关注的是数据点"方向"上的相似(如文档主题、用户偏好), 那么余弦相似度(或余弦距离)才是你的利器,但这时需要使用支持自定义距离的聚类算法或自己实现 K-Means。
  • 特征缩放再强调: 无论选择哪种距离度量,如果特征的尺度差异很大,**特征缩放(如标准化 Standard Scaling 或归一化 Min-Max Scaling)**几乎总是必不可少的步骤。否则,范围大的特征将主导距离计算,掩盖其他特征的重要性。

  • K-Means与质心更新的内在联系: K-Means 算法的质心更新过程是计算簇内点的均值。在数学上,这个"均值"操作是最小化簇内欧氏距离平方和 的最佳质心。如果使用曼哈顿距离,理论上最佳的质心应该是簇内所有点的中位数 (而非均值),以最小化簇内曼哈顿距离和。因此,如果需要用曼哈顿距离运行 K-Means,不仅仅是距离函数要变,质心更新的逻辑也应该从求均值变为求中位数 ,这才是真正的深度定制。sklearnKMeans 由于内部优化,无法直接更换距离和对应的更新逻辑,这也是我们理解其工作原理的重要性所在。

小结与展望:精准度量,洞察数据真谛

理解距离度量的选择,是 K-Means 实践中非常重要的一环。它要求我们不仅会使用算法,更要能理解其底层机制,并根据实际需求进行灵活调整。

在接下来的文章中,我们将继续深入 K-Means 的局限性,并探索它在图像压缩和市场细分中的神奇应用。


相关推荐
程序员-King.2 小时前
day146—递归—验证二叉搜索树(LeetCode-98)
算法·leetcode·二叉树·递归
tobias.b2 小时前
408真题解析-2009-41-数据结构-最短路径
数据结构·算法·计算机考研·408考研·408真题解析
王老师青少年编程2 小时前
2024年9月GESP真题及题解(C++七级): 矩阵移动
c++·算法·题解·真题·gesp·七级·矩阵移动
海绵宝宝de派小星2 小时前
什么是人工智能?AI、机器学习、深度学习的关系
人工智能·深度学习·机器学习·ai
棒棒的皮皮2 小时前
【深度学习】YOLO 进阶提升之算法改进(新型骨干网络 / 特征融合方法 / 损失函数设计)
深度学习·算法·yolo·计算机视觉
一招定胜负2 小时前
机器学习项目:矿物分类系统重制版
人工智能·机器学习·分类
pas1362 小时前
33-mini-vue 更新element的children-双端对比diff算法
javascript·vue.js·算法
jay神2 小时前
车牌识别与定位数据集-CCPD2020
人工智能·深度学习·机器学习
三块可乐两块冰2 小时前
【第二十六周】机器学习笔记二十七
算法·机器学习·支持向量机