news 2026/7/4 17:17:17

8种距离度量Python实战:从欧式到马氏,5行代码实现KNN分类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
8种距离度量Python实战:从欧式到马氏,5行代码实现KNN分类

8种距离度量Python实战:从欧式到马氏,5行代码实现KNN分类

在机器学习领域,距离度量是许多算法的核心基础。无论是KNN分类、聚类分析还是推荐系统,选择合适的距离度量方式直接影响模型性能。本文将带你深入理解8种经典距离度量方法,并通过Python实战演示它们在KNN分类中的应用效果。

1. 距离度量的基础概念

距离度量是衡量数据点之间相似性或差异性的数学工具。在机器学习中,我们经常需要计算样本之间的距离,这直接影响模型的预测结果。不同的距离度量方法适用于不同的数据特征和应用场景。

为什么距离度量如此重要?

想象一下,如果你要判断一个新样本属于哪个类别,最直观的方法就是看它与哪些已知样本最"接近"。这里的"接近"就需要通过距离度量来量化。选择不当的距离度量可能导致模型性能下降,甚至得出完全错误的结论。

常见应用场景包括:

  • 分类算法(如KNN)
  • 聚类分析(如K-Means)
  • 异常检测
  • 推荐系统
  • 图像识别

在开始具体介绍前,我们先准备好实验环境。确保已安装以下Python库:

import numpy as np from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score from scipy.spatial.distance import mahalanobis

2. 欧式距离与曼哈顿距离

2.1 欧式距离(Euclidean Distance)

欧式距离是最直观的距离度量方式,源于我们日常的几何空间概念。它计算的是两点之间的直线距离,公式为:

$$ d(x,y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2} $$

Python实现:

def euclidean_distance(x, y): return np.sqrt(np.sum((x - y)**2)) # 示例 point1 = np.array([1, 2, 3]) point2 = np.array([4, 5, 6]) print(f"欧式距离: {euclidean_distance(point1, point2):.2f}")

特点:

  • 对数据尺度敏感,使用时通常需要标准化
  • 对异常值敏感
  • 适用于连续型数据

2.2 曼哈顿距离(Manhattan Distance)

曼哈顿距离又称城市街区距离,得名于在曼哈顿街区行走的路径。它计算的是各维度绝对差之和:

$$ d(x,y) = \sum_{i=1}^n |x_i - y_i| $$

Python实现:

def manhattan_distance(x, y): return np.sum(np.abs(x - y)) print(f"曼哈顿距离: {manhattan_distance(point1, point2):.2f}")

应用场景对比:

指标欧式距离曼哈顿距离
计算方式平方和开方绝对值和
敏感性对异常值敏感对异常值相对稳健
适用场景物理空间距离网格状路径规划
计算效率中等(涉及平方运算)高(仅绝对值运算)

提示:在高维数据中,曼哈顿距离往往比欧式距离表现更稳定,因为各维度差异的累加效应更明显。

3. 切比雪夫距离与闵可夫斯基距离

3.1 切比雪夫距离(Chebyshev Distance)

切比雪夫距离源于国际象棋中国王的移动方式,计算的是各维度绝对差的最大值:

$$ d(x,y) = \max_i |x_i - y_i| $$

Python实现:

def chebyshev_distance(x, y): return np.max(np.abs(x - y)) print(f"切比雪夫距离: {chebyshev_distance(point1, point2):.2f}")

典型应用:

  • 棋盘游戏AI
  • 图像处理中的像素比较
  • 工业质量控制中的公差检测

3.2 闵可夫斯基距离(Minkowski Distance)

闵可夫斯基距离是欧式距离和曼哈顿距离的推广,通过参数p控制距离类型:

$$ d(x,y) = \left( \sum_{i=1}^n |x_i - y_i|^p \right)^{1/p} $$

Python实现:

def minkowski_distance(x, y, p): return np.sum(np.abs(x - y)**p)**(1/p) # p=2时等同于欧式距离 print(f"闵可夫斯基距离(p=2): {minkowski_distance(point1, point2, 2):.2f}") # p=1时等同于曼哈顿距离 print(f"闵可夫斯基距离(p=1): {minkowski_distance(point1, point2, 1):.2f}")

参数p的影响:

  • p=1:曼哈顿距离
  • p=2:欧式距离
  • p→∞:趋近于切比雪夫距离

注意:闵可夫斯基距离虽然灵活,但选择合适的p值需要基于具体问题和交叉验证。

4. 余弦相似度与汉明距离

4.1 余弦相似度(Cosine Similarity)

余弦相似度衡量的是两个向量的夹角余弦值,关注方向而非大小:

$$ \text{similarity} = \frac{x \cdot y}{|x| |y|} $$

Python实现:

def cosine_similarity(x, y): dot_product = np.dot(x, y) norm_x = np.linalg.norm(x) norm_y = np.linalg.norm(y) return dot_product / (norm_x * norm_y) # 余弦距离=1-余弦相似度 print(f"余弦相似度: {cosine_similarity(point1, point2):.2f}")

适用场景:

  • 文本相似度计算(TF-IDF向量)
  • 推荐系统中的用户偏好比较
  • 高维稀疏数据

4.2 汉明距离(Hamming Distance)

汉明距离用于比较两个等长字符串在相同位置上不同字符的数量:

def hamming_distance(str1, str2): if len(str1) != len(str2): raise ValueError("字符串长度必须相同") return sum(c1 != c2 for c1, c2 in zip(str1, str2)) print(f"汉明距离: {hamming_distance('1011101', '1001001')}")

典型应用:

  • 错误检测与纠正编码
  • DNA序列比对
  • 密码学中的差异分析

5. 马氏距离及其特性

马氏距离(Mahalanobis Distance)是一种考虑数据分布特性的距离度量,能够解决特征间相关性和尺度不一致的问题:

$$ D_M(x,y) = \sqrt{(x-y)^T S^{-1} (x-y)} $$

其中S是协方差矩阵。

Python实现:

# 计算马氏距离需要先计算协方差矩阵的逆 iris = load_iris() X = iris.data cov_matrix = np.cov(X, rowvar=False) inv_cov_matrix = np.linalg.inv(cov_matrix) def mahalanobis_distance(x, y, inv_cov): diff = x - y return np.sqrt(diff.T @ inv_cov @ diff) # 示例计算两个样本间的马氏距离 sample1 = X[0] sample2 = X[1] print(f"马氏距离: {mahalanobis_distance(sample1, sample2, inv_cov_matrix):.2f}")

马氏距离的独特优势:

  1. 自动处理特征间的相关性
  2. 不受特征尺度影响
  3. 考虑数据分布形状

注意:当协方差矩阵为单位矩阵时,马氏距离退化为欧式距离。

6. KNN分类实战比较

现在我们将这8种距离度量应用于Iris数据集的KNN分类,比较它们的性能差异。

6.1 数据准备

# 加载数据 iris = load_iris() X, y = iris.data, iris.target # 划分训练测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 定义距离度量列表 distance_metrics = [ ('euclidean', '欧式距离'), ('manhattan', '曼哈顿距离'), ('chebyshev', '切比雪夫距离'), ('minkowski', '闵可夫斯基距离(p=3)'), ('cosine', '余弦距离'), ('hamming', '汉明距离'), ('mahalanobis', '马氏距离') ]

6.2 模型训练与评估

results = [] for metric, name in distance_metrics: if metric == 'mahalanobis': # 马氏距离需要特殊处理 cov_matrix = np.cov(X_train, rowvar=False) inv_cov_matrix = np.linalg.inv(cov_matrix) knn = KNeighborsClassifier(n_neighbors=5, metric=lambda x, y: mahalanobis(x, y, inv_cov_matrix)) else: knn = KNeighborsClassifier(n_neighbors=5, metric=metric) knn.fit(X_train, y_train) y_pred = knn.predict(X_test) acc = accuracy_score(y_test, y_pred) results.append((name, acc))

6.3 结果对比

print("不同距离度量在KNN中的表现:") for name, acc in sorted(results, key=lambda x: x[1], reverse=True): print(f"{name:<20}: 准确率 {acc:.4f}")

典型输出结果可能如下(具体值可能因数据划分不同而变化):

马氏距离 : 准确率 0.9778 欧式距离 : 准确率 0.9556 曼哈顿距离 : 准确率 0.9556 闵可夫斯基距离(p=3): 准确率 0.9556 切比雪夫距离 : 准确率 0.9333 余弦距离 : 准确率 0.9111 汉明距离 : 准确率 0.3111

6.4 结果分析

从实验结果可以看出:

  1. 马氏距离表现最佳,因为它考虑了特征间的相关性
  2. 欧式、曼哈顿和闵可夫斯基距离表现相当
  3. 汉明距离表现最差,因为它不适合连续型数据

实际应用中,距离度量的选择应该基于数据特性和业务需求,而不是盲目选择准确率最高的方法。

7. 距离度量的选择指南

如何为你的项目选择合适距离度量?以下是一些实用建议:

数据类型考虑:

  • 连续型数据:欧式、曼哈顿、马氏距离
  • 离散型数据:汉明距离
  • 文本数据:余弦相似度

问题特性考虑:

  • 特征尺度差异大:马氏距离或标准化后使用欧式距离
  • 高维数据:余弦相似度或曼哈顿距离
  • 网格状结构:曼哈顿或切比雪夫距离

实用选择流程:

  1. 分析数据特征(尺度、相关性、维度)
  2. 初步筛选几种候选距离度量
  3. 通过交叉验证比较性能
  4. 考虑计算效率(特别是大规模数据时)

8. 高级应用与优化技巧

8.1 自定义距离度量

Scikit-learn允许自定义距离度量。例如,实现加权欧式距离:

def weighted_euclidean(x, y, weights=[1,1,1,1]): return np.sqrt(np.sum(weights * (x - y)**2)) # 使用自定义距离的KNN knn_custom = KNeighborsClassifier( n_neighbors=5, metric=lambda x, y: weighted_euclidean(x, y, weights=[0.1, 0.3, 0.3, 0.3]) )

8.2 距离度量预处理技巧

  1. 标准化处理:对欧式距离等尺度敏感的度量尤为重要

    from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test)
  2. 特征选择:去除不相关特征可以提高距离度量的有效性

  3. 维度缩减:对高维数据使用PCA等降维技术

8.3 混合距离度量

对于包含不同类型特征的数据集,可以考虑为不同类型特征使用不同距离度量,然后组合结果。例如:

def mixed_distance(x, y): # 前两个特征使用曼哈顿距离 num_part = np.sum(np.abs(x[:2] - y[:2])) # 后两个特征使用欧式距离 cat_part = np.sqrt(np.sum((x[2:] - y[2:])**2)) return num_part + cat_part

9. 性能优化与加速

对于大规模数据集,距离计算可能成为性能瓶颈。以下是一些优化策略:

  1. 使用KD树或Ball树

    knn = KNeighborsClassifier(algorithm='kd_tree') # 或 'ball_tree'
  2. 近似最近邻:使用近似算法如LSH(Locality-Sensitive Hashing)

  3. 并行计算:利用多核CPU或GPU加速

  4. 距离矩阵缓存:对于静态数据,预计算并存储距离矩阵

from sklearn.neighbors import DistanceMetric dist = DistanceMetric.get_metric('euclidean') distance_matrix = dist.pairwise(X_train)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/4 17:16:44

MonikA.I:AI驱动的游戏角色交互革命

MonikA.I&#xff1a;AI驱动的游戏角色交互革命 【免费下载链接】MonikA.I Submod for MAS with AI based features 项目地址: https://gitcode.com/gh_mirrors/mo/MonikA.I 在传统的视觉小说游戏中&#xff0c;角色对话往往受限于预设脚本&#xff0c;玩家与虚拟角色的…

作者头像 李华
网站建设 2026/7/4 17:14:47

YOLOv8与BoT-SORT实现高效实时人物跟踪系统

1. 项目概述&#xff1a;YOLO实时人物跟踪系统 在计算机视觉领域&#xff0c;实时人物跟踪一直是个极具挑战性的任务。传统方案要么计算复杂度太高难以实时运行&#xff0c;要么跟踪精度不足难以实用。而基于YOLO&#xff08;You Only Look Once&#xff09;的目标检测框架&…

作者头像 李华
网站建设 2026/7/4 17:13:59

多语言命名实体识别技术:挑战与Onomas-CNN X解决方案

1. 多语言命名实体分类的技术挑战与现状命名实体识别&#xff08;NER&#xff09;作为自然语言处理的基础任务&#xff0c;其核心价值在于从非结构化文本中提取人名、地名、组织机构名等关键信息。在实际业务场景中&#xff0c;我们经常需要处理跨语言、跨文化的实体识别问题。…

作者头像 李华
网站建设 2026/7/4 17:13:42

IIM-42652与STM32L041C6的6DoF运动跟踪系统设计

1. IIM-42652与STM32L041C6的硬件组合解析 IIM-42652是TDK旗下InvenSense推出的6轴MEMS惯性测量单元(IMU)&#xff0c;集成了3轴陀螺仪和3轴加速度计。这款工业级传感器采用2.53.00.91mm的超小封装&#xff0c;支持I2C/I3C/SPI通信接口&#xff0c;陀螺仪量程可配置为15.625dps…

作者头像 李华
网站建设 2026/7/4 17:11:06

多维聚合中的数据操纵:Pre/Post聚合操作实战指南

1. 项目概述&#xff1a;当数据聚合从“加总”走向“空间折叠”你有没有遇到过这样的场景&#xff1a;销售报表里&#xff0c;区域经理要按“省份→城市→门店”三级下钻看毛利&#xff0c;财务总监却需要把同一份数据按“产品线→季度→销售渠道”重新切片分析&#xff0c;而风…

作者头像 李华
网站建设 2026/7/4 17:10:56

MLOps建模实战:从指标驱动到可交付决策链

1. 这不是“建模指南”&#xff0c;而是一份MLOps工程师的建模现场手记 你打开这份笔记时&#xff0c;大概率正被三件事同时拉扯&#xff1a;模型在本地跑得飞起&#xff0c;一上生产环境就报错&#xff1b;特征工程脚本改了五版&#xff0c;但线上A/B测试结果还是对不上&#…

作者头像 李华