数据点的“外交间隔”:权衡它们之间的相似与差别

[复制链接]
发表于 2025-12-15 08:12:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在数据分析的天下里, “间隔” 不但仅是舆图上两点之间的旅程。
间隔 ,本质上是权衡两个事物 “相似度” 的尺子。

  • 间隔越近 = 相似度越高
  • 间隔越远 = 差别越大
假如你想做用户画像聚类、想做商品保举体系,大概想辨认名誉卡诓骗交易业务,你起主要选对这把“尺子”。
本文将带你全面相识数据分析中常用的各种间隔度量,从最直观的欧氏间隔到复杂的时间序列间隔。
为了方便明确,我将它们分为了五大门派。
1. 第一门派:多少空间的丈量者

这一类间隔最符合我们的直觉,通常用于处置处罚数值型数据(比如身高、体重、经纬度)。
1.1. 欧氏间隔:最直观的“直线间隔”

欧氏间隔就是我们常说的 “直线间隔”。
在二维平面上,两点间的欧氏间隔就是毗连它们的直线长度。
应用场景:

  • 外卖配送: 假设你是无人机送外卖,不受门路限定,直接飞已往,这就是欧氏间隔。
  • K-Means 聚类: 最常用的间隔度量。
代码示例:
  1. import numpy as np
  2. # 后面的代码示例多次用到 distance,不再重复引用了
  3. from scipy.spatial import distance
  4. # 两个用户的特征:[活跃时长(小时), 消费金额(元)]
  5. user_A = [2.5, 300]
  6. user_B = [3.0, 350]
  7. d_euclidean = distance.euclidean(user_A, user_B)
  8. print(f"欧氏距离: {d_euclidean:.2f}")
  9. # 运行结果:
  10. '''
  11. 欧氏距离: 50.00
  12. '''
复制代码
图形化结果如下:

注意:欧氏间隔对数据的尺度敏感!假如特性的单元差别(如年龄和收入),直接盘算会导致收入特性主导间隔盘算。
1.2. 曼哈顿间隔:都会街区的走法

想象在纽约曼哈顿的街道上行走,你不能斜穿大楼,只能沿着街道走。曼哈顿间隔就是这种 “都会街区间隔”。
应用场景:

  • 都会物流: 真实的快递员配送路径估算。
  • 高维数据: 在某些高维数据中,曼哈顿间隔比欧氏间隔更能抗干扰(Robust)。
代码示例:
  1. # 外卖配送示例:从餐厅到顾客的路径
  2. restaurant = np.array([3, 7])  # 坐标(3,7)
  3. customer = np.array([8, 2])  # 坐标(8,2)
  4. euclidean = distance.euclidean(restaurant, customer)
  5. manhattan = distance.cityblock(restaurant, customer)
  6. print(f"餐厅到顾客的直线距离(欧氏): {euclidean:.2f}")
  7. print(f"餐厅到顾客的街区距离(曼哈顿): {manhattan:.2f}")
  8. # 运行结果:
  9. '''
  10. 餐厅到顾客的直线距离(欧氏): 7.07
  11. 餐厅到顾客的街区距离(曼哈顿): 10.00
  12. '''
复制代码

1.3. 切比雪夫间隔:棋盘上的王者

也就是国际象棋中“国王”移动的步数。国王可以横着走、竖着走,也能斜着走,且步数都算 1。
它只在乎数值差最大的谁人维度。
应用场景:

  • 仓储物流: 龙门吊抓取货品,横向移动和纵向移动可以同时举行,时间取决于最远的谁人方向。
代码示例:
  1. d_chebyshev = distance.chebyshev(user_A, user_B)
  2. print(f"切比雪夫距离: {d_chebyshev:.2f}")
复制代码
1.4. 闵可夫斯基间隔:间隔的通用公式

它是上面三种间隔的“爸爸”。通过一个参数 p 来控制:

  • 当 p=1 时,就是曼哈顿间隔。
  • 当 p=2 时,就是欧氏间隔。
  • 当 p=∞ 时,就是切比雪夫间隔。
应用场景: 当你不确定用哪种多少间隔时,可以调治 p 值来探求最优解。
代码示例:
  1. # 对比不同p值的效果
  2. point1 = np.array([0, 0])
  3. point2 = np.array([3, 4])
  4. p_values = [1, 2, 3, 5, 10]
  5. distances = []
  6. for p in p_values:
  7.     dist = distance.minkowski(point1, point2, p)
  8.     distances.append(dist)
  9.     print(f"p={p}: 距离={dist:.2f}")
  10. # 运行结果:
  11. '''
  12. p=1: 距离=7.00
  13. p=2: 距离=5.00
  14. p=3: 距离=4.50
  15. p=5: 距离=4.17
  16. p=10: 距离=4.02
  17. '''
复制代码

2. 第二门派:方向与相干性的探索者

这一类间隔不关心 “数值巨细”,更关心 “趋势方向” 或 “统计关系”。
2.1. 余弦间隔:关注方向而非巨细

余弦间隔权衡的是两个向量方向的差别,而不是它们的巨细差别。
这在文天职析中特殊有用,由于文档的长度差别,但主题大概相似。
应用场景:

  • 文本相似度(热门): 比如比力两篇文章。文章 A 只有 100 字,文章 B 有 10000 字,固然词频数值差很大,但假如它们都在讲“人工智能”,它们的方向(角度)是划一的。
  • 保举体系: 用户打分偏好。
代码示例:(用几个简单的消息标题来盘算余弦相似度)
  1. # 文本向量(假设是词频):[AI, 苹果, 股票]
  2. doc_1 = [10, 0, 5]  # 科技财经文
  3. doc_2 = [20, 0, 10] # 长篇科技财经文(方向一致)
  4. doc_3 = [0, 10, 0]  # 水果文
  5. # 余弦距离 = 1 - 余弦相似度
  6. # 接近0,表示非常相似
  7. print(f"同类文章余弦距离: {distance.cosine(doc_1, doc_2):.2f}")
  8. # 接近1,表示无关
  9. print(f"不同类文章余弦距离: {distance.cosine(doc_1, doc_3):.2f}")
  10. # 运行结果:
  11. '''
  12. 同类文章余弦距离: 0.00
  13. 不同类文章余弦距离: 1.00
  14. '''
复制代码
2.2. 相干系数间隔:权衡线性关系

基于皮尔逊相干系数的间隔,权衡两个变量之间线性相干性的差别。
应用场景:

  • 股票分析: 权衡两只股票的走势是否同步。假如一支涨另一支也涨,它们的相干间隔就很小,哪怕一个股价是 10 元,另一个是 1000 元。
  1. # 两只股票过去5天的涨跌幅
  2. stock_A = [0.1, -0.2, 0.3, 0.1, 0.0]
  3. stock_B = [0.2, -0.4, 0.6, 0.2, 0.0] # 走势完全也就是2倍关系
  4. d_correlation = distance.correlation(stock_A, stock_B)
  5. print(f"相关系数距离: {d_correlation:.2f}")
  6. # 运行结果
  7. '''
  8. 相关系数距离: 0.00
  9. '''
复制代码
可以实验调解调解stock_A和stock_B的数值,再看看相干系数的变革。
2.3. 马氏间隔:思量数据分布的间隔

马氏间隔思量了数据的协方差布局,是一种尺度无关且清除了特性相干性的间隔度量。
应用场景:

  • 非常检测: 假设你统计人的身高和体重。假如你用欧氏间隔,一个 190cm、50kg 的人大概离中心点不远。但思量到身高体重的正相干性(高的人通常重),这个数据点在马氏间隔下就会非常远(非常非常)。
  1. # 需要先计算协方差矩阵的逆
  2. np.random.seed(42)
  3. height = np.random.normal(170, 10, 20)  # 20个身高样本
  4. weight = height * 0.5 + np.random.normal(0, 5, 20)  # 体重与身高相关
  5. data = np.column_stack([height, weight])
  6. cov_matrix = np.cov(data.T)
  7. inv_cov_matrix = np.linalg.inv(cov_matrix)
  8. point_1 = [170, 60] # 正常点
  9. point_2 = [190, 50] # 异常点(又高又瘦)
  10. d_mah_1 = distance.mahalanobis(point_1, np.mean(data, axis=0), inv_cov_matrix)
  11. d_mah_2 = distance.mahalanobis(point_2, np.mean(data, axis=0), inv_cov_matrix)
  12. print(f"正常点马氏距离: {d_mah_1:.2f}")
  13. print(f"异常点马氏距离: {d_mah_2:.2f}") # 距离会很大
  14. # 运行结果:
  15. '''
  16. 正常点马氏距离: 4.93
  17. 异常点马氏距离: 9.06
  18. '''
复制代码
3. 第三门派:聚集与分类的裁判

当数据不是数字,而是分类、标签或字符串时,我们用这些。
3.1. 杰卡德间隔:聚集的相似度

杰卡德间隔权衡两个聚集的差别程度,通过盘算交集与并集的比例得到。
应用场景:

  • 电商保举: 用户 A 买了 {苹果, 香蕉},用户 B 买了 {苹果, 香蕉, 西瓜}。通过杰卡德间隔盘算他们的购买重合度,进而保举商品。
  1. d_jaccard = distance.jaccard([1, 1, 0], [1, 1, 1]) # boolean vector
  2. print(f"杰卡德距离: {d_jaccard:.2f}")
  3. # 运行结果:
  4. '''
  5. 杰卡德距离: 0.33
  6. '''
复制代码
3.2. 汉明间隔:字符串的差别度量

汉明间隔权衡两个等长字符串在对应位置上差别字符的数目。
应用场景:

  • 拼写纠错: "banana" 和 "banane",只有一个字母差别,汉明间隔为 1。
  • 信息编码: 通讯中检测数据传输是否堕落。
  1. d_hamming = distance.hamming([1, 0, 1], [1, 0, 0])
  2. print(f"汉明距离: {d_hamming:.2f}") # 输出比例,有些库输出个数
  3. # 运行结果:
  4. '''
  5. 汉明距离: 0.33
  6. '''
复制代码
3.3. 编辑间隔:字符串转换的代价

编辑间隔(Levenshtein间隔)权衡将一个字符串转换为另一个字符串所需的最少单字符编辑使用次数(插入、删除、更换)。
应用场景:

  • 搜刮引擎: 你输错单词时,百度/谷歌提示“您是不是要找...”,就是通过编辑间隔找到最靠近的准确词。
  1. # 注:标准库无此函数,通常用 pip install Levenshtein 或自定义
  2. # 这里用简单的逻辑演示概念
  3. def simple_levenshtein(s1, s2):
  4.     if len(s1) < len(s2):
  5.         return simple_levenshtein(s2, s1)
  6.     if len(s2) == 0:
  7.         return len(s1)
  8.     previous_row = range(len(s2) + 1)
  9.     for i, c1 in enumerate(s1):
  10.         current_row = [i + 1]
  11.         for j, c2 in enumerate(s2):
  12.             insertions = previous_row[j + 1] + 1
  13.             deletions = current_row[j] + 1
  14.             substitutions = previous_row[j] + (c1 != c2)
  15.             current_row.append(min(insertions, deletions, substitutions))
  16.         previous_row = current_row
  17.     return previous_row[-1]
  18. print(f"编辑距离 ('kitten', 'sitting'): {simple_levenshtein('kitten', 'sitting')}")
  19. # 运行结果:
  20. '''
  21. 编辑距离 ('kitten', 'sitting'): 3
  22. '''
复制代码
4. 第四门派:分布差别的判定师

用于权衡两个“概率分布”(比如两个直方图)有多像。这在呆板学习和天生式 AI 中非常火。
4.1. KL 散度:权衡概率分布差别

KL散度权衡一个概率分布与另一个参考分布之间的差别,但不是对称的。
应用场景:

  • 呆板学习训练: 权衡模子猜测的概率分布与真实标签分布之间的差别(Loss Function)。
  1. from scipy.stats import entropy
  2. p = [0.1, 0.9] # 真实分布
  3. q = [0.2, 0.8] # 预测分布
  4. kl_div = entropy(p, q)
  5. print(f"KL散度: {kl_div:.4f}")
  6. # 运行结果:
  7. '''
  8. KL散度: 0.0367
  9. '''
复制代码
4.2. JS 散度:权衡概率分布差别-对称

JS散度是KL散度的对称版本,值域固定。
应用场景:

  • GAN (天生对抗网络): 早期用于权衡天生图片分布与真实图片分布的相似度。
  1. d_js = distance.jensenshannon(p, q)
  2. print(f"JS散度: {d_js:.4f}")
  3. # 运行结果:
  4. '''
  5. JS散度: 0.0998
  6. '''
复制代码
4.3. Wasserstein 间隔:地球搬运间隔

Wasserstein间隔权衡将一个概率分布"搬运"成另一个所需的最小工作量,直观明确是将一堆沙子变成指定形状所需的最小移动间隔。
应用场景:

  • 图像天生 (WGAN): 纵然两个分布完全不重叠(KL 散度会失效),Wasserstein 间隔也能给出公道的数值,引导 AI 学习。
  1. from scipy.stats import wasserstein_distance
  2. d_wasserstein = wasserstein_distance([0, 1, 3], [5, 6, 8])
  3. print(f"Wasserstein距离: {d_wasserstein:.2f}")
  4. # 运行结果:
  5. '''
  6. Wasserstein距离: 5.00
  7. '''
复制代码
5. 第五门派:时间序列的变形者

5.1. DTW 间隔:时间序列的弹性匹配

动态时间规整(DTW)间隔允许时间轴伸缩弯曲,用于权衡两个时间序列的相似性,纵然它们在时间轴上不完全对齐。
应用场景:

  • 语音辨认/股票分析: 两个人读同一个单词 "Hello"。

    • 人 A:H-e-l-l-o (语速快)
    • 人 B:H-e-e-e-l-l-o-o (语速慢)
    • 欧氏间隔会以为这完全差别,但 DTW 会把时间轴“对齐”,发现它们实在很像。

  1. # 简单的DTW概念代码(实际应用推荐使用 fastdtw 库)
  2. from scipy.spatial.distance import euclidean
  3. def dtw_distance(s1, s2):
  4.     n, m = len(s1), len(s2)
  5.     dtw_matrix = np.zeros((n+1, m+1))
  6.     dtw_matrix[0, 1:] = np.inf
  7.     dtw_matrix[1:, 0] = np.inf
  8.     for i in range(1, n+1):
  9.         for j in range(1, m+1):
  10.             cost = abs(s1[i-1] - s2[j-1])
  11.             dtw_matrix[i, j] = cost + min(dtw_matrix[i-1, j],    # 插入
  12.                                           dtw_matrix[i, j-1],    # 删除
  13.                                           dtw_matrix[i-1, j-1])  # 匹配
  14.     return dtw_matrix[n, m]
  15. ts_1 = [1, 2, 3, 4]
  16. ts_2 = [1, 1, 2, 3, 4, 4] # 同样趋势,但多了重复(慢动作)
  17. print(f"DTW距离: {dtw_distance(ts_1, ts_2)}")
  18. # 运行结果:
  19. '''
  20. DTW距离: 0.0
  21. '''
复制代码
6. 总结:怎样选择你的“尺子”?

面临新数据,别盲目选欧氏间隔,参考下面的发起:

  • 平常数值数据,看绝对巨细: 选 欧氏 或 曼哈顿。
  • 看重方向/喜欢,忽略绝对数值: 选 余弦间隔(如文本、保举)。
  • 看重趋势变革,忽略数值巨细: 选 相干系数间隔(如股票)。
  • 数据相干性强,且有离群点: 选 马氏间隔。
  • 聚集、标签类数据: 选 杰卡德 或 汉明。
  • 概率分布对比(AI 模子): 选 KL 或 Wasserstein。
  • 是非不一的时间序列: 选 DTW。
文中代码中大部分的间隔关键是把握其概念和应用场景,至于其间隔算法的实现,scipy库中大部分都有封装好的函数,纵然没有,也可以用其他库来代替。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表