简介
在数据分析、路径规划、机器学习这些场景里,经常要算两个点/向量之间的“距离”,欧氏、曼哈顿、切比雪夫是最基础也最常用的三种,我结合公式和Python代码把它们捋清楚,记下来方便后续用,尽量写得直白,重点在“能看懂、能复用”。
1. 欧氏距离(Euclidean Distance)
核心说明
欧式距离就是咱们最直观的“直线距离”,比如平面上两点间的直线长度,三维空间里两点间的直线长度,本质是勾股定理的延伸,也是最符合日常认知的距离计算方式。
公式
(1) 二维平面上两点 $a(x_1, y_1)$ 和 $b(x_2,y_2)$ 的直线距离:
$d(a,b) = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}$
(2) 三维空间两点 $a(x_1,y_1,z_1)$、$b(x_2,y_2,z_2)$ 间的欧氏距离:
$d(a,b) = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + (z_2 - z_1)^2}$
(3) 两个n维向量 $a(x_{11},x_{12},\dots,x_{1n})$ 和 $b(x_{21},x_{22},\dots,x_{2n})$ 间的欧氏距离:
$d(a,b) = \sqrt{\sum_{i=1}^n (x_{2i} - x_{1i})^2}$
也可以表示成向量运算的形式:
$d(a,b) = \sqrt{(a - b)^T(a - b)}$
Python实现(支持n维向量)
import math
def euclidean_distance(a, b):
"""
计算两个n维向量的欧氏距离
:param a: 第一个向量(列表/元组,如[1,50.6]、[1,2,3])
:param b: 第二个向量(维度需和a一致)
:return: 欧氏距离值
"""
if len(a) != len(b):
raise ValueError("两个向量的维度必须一致!")
# 先算每个维度差值的平方和,再开平方
squared_sum = sum((x - y)**2 for x, y in zip(a, b))
return math.sqrt(squared_sum)
# 测试案例
# 二维案例(原示例)
test_a_2d = [1, 50.6]
test_b_2d = [1, 1]
print(f"二维欧氏距离:{euclidean_distance(test_a_2d, test_b_2d)}") # 输出49.6
# 三维案例
test_a_3d = [1, 2, 3]
test_b_3d = [4, 5, 6]
print(f"三维欧氏距离:{euclidean_distance(test_a_3d, test_b_3d)}") # 输出√(9+9+9)=√27≈5.1962. 曼哈顿距离(Manhattan Distance)
核心说明
曼哈顿距离也叫“城市街区距离”,不是直线距离,而是像在城市里走路一样,只能沿横竖方向走,算的是“横向+纵向”的总路程,比如从A点到B点,绕着街区走的总距离。
公式
(1) 二维平面两点 $a(x_1,y_1)$ 和 $b(x_2,y_2)$ 间的曼哈顿距离:
$d(a,b) = |x_2 - x_1| + |y_2 - y_1|$
(2) 两个n维向量 $a(x_{11},x_{12},\dots,x_{1n})$ 与 $b(x_{21},x_{22},\dots,x_{2n})$ 间的曼哈顿距离:
$d(a,b) = \sum_{i=1}^n |x_{2i} - x_{1i}|$
Python实现(支持n维向量)
def manhattan_distance(a, b):
"""
计算两个n维向量的曼哈顿距离
:param a: 第一个向量(列表/元组)
:param b: 第二个向量(维度需和a一致)
:return: 曼哈顿距离值
"""
if len(a) != len(b):
raise ValueError("两个向量的维度必须一致!")
# 累加每个维度差值的绝对值
return sum(abs(x - y) for x, y in zip(a, b))
# 测试案例
# 二维案例(原示例)
print(f"二维曼哈顿距离:{manhattan_distance(test_a_2d, test_b_2d)}") # 输出0 + 49.6 = 49.6
# 三维案例
print(f"三维曼哈顿距离:{manhattan_distance(test_a_3d, test_b_3d)}") # 输出3+3+3=93. 切比雪夫距离(Chebyshev Distance)
核心说明
切比雪夫距离可以理解成“国王距离”——国际象棋里国王走一步能到相邻8个方格中的任意一个,从A点到B点,国王最少需要走的步数就是切比雪夫距离,本质是两个点各维度差值的绝对值中最大的那个。
公式
(1) 二维平面两点 $a(x_1,y_1)$ 和 $b(x_2,y_2)$ 间的切比雪夫距离:
$d(a,b) = \max(|x_2 - x_1|, |y_2 - y_1|)$
(2) 两个n维向量 $a(x_{11},x_{12},\dots,x_{1n})$ 和 $b(x_{21},x_{22},\dots,x_{2n})$ 间的切比雪夫距离:
$d(a,b) = \max_{i=1}^n |x_{2i} - x_{1i}|$
Python实现(支持n维向量)
def chebyshev_distance(a, b):
"""
计算两个n维向量的切比雪夫距离
:param a: 第一个向量(列表/元组)
:param b: 第二个向量(维度需和a一致)
:return: 切比雪夫距离值
"""
if len(a) != len(b):
raise ValueError("两个向量的维度必须一致!")
# 取每个维度差值绝对值的最大值
return max(abs(x - y) for x, y in zip(a, b))
# 测试案例
# 二维案例(棋盘场景)
chess_a = (1, 1)
chess_b = (5, 4)
print(f"棋盘上国王从{chess_a}到{chess_b}的步数(切比雪夫距离):{chebyshev_distance(chess_a, chess_b)}") # 差值x=4,y=3,最大值4,输出4
# 原示例二维测试
print(f"原示例切比雪夫距离:{chebyshev_distance(test_a_2d, test_b_2d)}") # 差值x=0,y=49.6,最大值49.6,输出49.6
# 三维案例
print(f"三维切比雪夫距离:{chebyshev_distance(test_a_3d, test_b_3d)}") # 差值都是3,最大值3,输出34. 三种距离的整合调用
整合代码
def calculate_distance(a, b, distance_type="euclidean"):
"""
统一计算三种距离的封装函数
:param a: 第一个向量
:param b: 第二个向量
:param distance_type: 距离类型,可选"euclidean"/"manhattan"/"chebyshev"
:return: 对应类型的距离值
"""
if len(a) != len(b):
raise ValueError("两个向量维度必须一致!")
if distance_type == "euclidean":
return euclidean_distance(a, b)
elif distance_type == "manhattan":
return manhattan_distance(a, b)
elif distance_type == "chebyshev":
return chebyshev_distance(a, b)
else:
raise ValueError("距离类型仅支持euclidean/manhattan/chebyshev!")
# 批量测试
test_vec1 = [2, 5, 8]
test_vec2 = [6, 9, 12]
print(f"批量测试 - 欧氏距离:{calculate_distance(test_vec1, test_vec2, 'euclidean')}") # √(16+16+16)=√48≈6.928
print(f"批量测试 - 曼哈顿距离:{calculate_distance(test_vec1, test_vec2, 'manhattan')}") # 4+4+4=12
print(f"批量测试 - 切比雪夫距离:{calculate_distance(test_vec1, test_vec2, 'chebyshev')}") # 最大值4闵可夫斯基距离(三种统一)
其实欧氏、曼哈顿、切比雪夫都是“闵可夫斯基距离”的特例,公式如下:
$d(a,b) = \left( \sum_{i=1}^n |x_{2i} - x_{1i}|^p \right)^{\frac{1}{p}}$
- 当 $p=1$ 时,就是曼哈顿距离;
- 当 $p=2$ 时,就是欧氏距离;
- 当 $p \to \infty$ 时,就是切比雪夫距离。
def minkowski_distance(a, b, p):
"""
计算闵可夫斯基距离(p为参数,覆盖三种基础距离)
:param a: 第一个向量
:param b: 第二个向量
:param p: 阶数(p=1→曼哈顿,p=2→欧氏,p越大越接近切比雪夫)
:return: 闵可夫斯基距离值
"""
if len(a) != len(b):
raise ValueError("两个向量维度必须一致!")
if p <= 0:
raise ValueError("p必须大于0!")
# p→∞时直接返回切比雪夫距离(简化版)
if p == float("inf"):
return chebyshev_distance(a, b)
sum_pow = sum(abs(x - y)**p for x, y in zip(a, b))
return sum_pow ** (1/p)
# 验证特例
print(f"p=1(曼哈顿):{minkowski_distance(test_vec1, test_vec2, 1)}") # 12,和之前一致
print(f"p=2(欧氏):{minkowski_distance(test_vec1, test_vec2, 2)}") # ≈6.928,和之前一致
print(f"p=∞(切比雪夫):{minkowski_distance(test_vec1, test_vec2, float('inf'))}") # 4,和之前一致5. 三种应用场景
| 距离类型 | 核心特点 | 典型应用场景 |
|---|---|---|
| 欧氏距离 | 直线距离,贴合直观认知 | 机器学习(相似度计算、KNN算法)、坐标定位、三维建模 |
| 曼哈顿距离 | 街区式路程,对异常值更稳健 | 路径规划(外卖配送、城市导航)、推荐系统(用户行为相似度) |
| 切比雪夫距离 | 最大维度差值,“步数”思维 | 棋盘类算法、物流配送(最大运输维度优化)、多维度决策 |
总结
- 欧氏、曼哈顿、切比雪夫是最基础的距离计算方式,核心区别在于“维度差值的处理方式”(平方和开方/绝对值和/绝对值最大值);
- 三种距离都能扩展到n维向量,代码实现时要注意“维度一致”的校验,避免报错;
- 闵可夫斯基距离是三者的统一形式,通过调整参数p可以切换不同距离类型,方便灵活调用;
- 实际使用时要根据场景选:要直线距离选欧氏,要路径总长度选曼哈顿,要“最少步数”选切比雪夫。
评论 (0)