1. 距离度量的直觉:两个坐标点之间的“路”
先从一个我实际踩过的坑说起。前阵子我给一个推荐系统做用户相似度计算,默认用了欧几里得距离,结果离线评测效果平平。后来换成曼哈顿距离,在同样的特征下,指标直接涨了好几个点。当时我就意识到,很多人在这两个距离上犯的错误,不是不知道公式,而是根本不清楚它们各自描述的是哪种“近”。
曼哈顿距离与欧几里得距离对比,看起来像是一个基础概念,但它直接影响 KNN、聚类、路径规划、推荐系统等一系列算法效果的走向。你不把它想透,后面所有用到距离的地方都会埋雷。
先看最朴素的直觉。欧几里得距离,也就是欧氏距离,是我们在纸上画一条直线测出来的长度;曼哈顿距离则像一个只能沿着横平竖直街道走的出租车司机,实际开的里程数。两个点的坐标固定,但这两条“路”的长短往往不一样。你从教学楼到图书馆,直线距离可能只有 300 米,但如果中间隔着人工湖,你实际走路绕一圈可能要 800 米,这就是欧氏距离和曼哈顿距离最典型的差异。
所以第一件事要搞清楚:距离度量的本质,不是“两点之间有多远”这个数学事实,而是“你的业务场景里,差异代价是按什么方式累积的”。选错距离,本质上就是选错了问题的度量模型。
1.1 欧几里得距离:直线最短的直觉
欧氏距离公式大家都很熟:
d = sqrt((x1 - x2)^2 + (y1 - y2)^2)扩展到 N 维就是所有维度差值的平方和,再开根号。
几何直觉就是一个直角三角形里斜边的长度。它符合我们最朴素的“直线最短”认知,所以在二维平面上,欧氏距离天然像是一个绕不开的基准。它还有一个非常重要的数学性质:旋转不变性。也就是说,你把整个坐标系旋转任意角度,点与点之间的欧氏距离保持不变。这种性质让它成为标准欧式空间里最自然的一种度量方式,很多算法默认用欧氏距离,不是因为它一定最优,而是因为它数学性质优雅,求导方便,形式简洁。
但问题恰恰出现在“直线可走”的假设上。真实世界里,大量数据并不满足这个假设。用户行为向量、文本特征、城市道路网络、基因表达数据,这些场景里,“坐标差值的平方再求和开根号”描述的根本不是实际代价的累积方式。
1.2 曼哈顿距离:只能走街区的逻辑
曼哈顿距离又叫城市街区距离、出租车距离。公式是:
d = |x1 - x2| + |y1 - y2|在 N 维空间里,就是对每一维差值的绝对值求和。名字源于美国曼哈顿区横平竖直的街道网络,出租车不能穿过建筑物,只能沿街区网格走,所以实际行驶距离是所有坐标差值的绝对值之和。
曼哈顿距离的优势是它能描述很多“非直线”的真实代价。路径规划、街区移动、网格系统,甚至在某些高维稀疏场景下,它比欧氏距离更稳定。更深一层看,曼哈顿距离对应的是 L1 范数,欧氏距离是 L2 范数。L1 范数对离群点不敏感,它不给大差值“平方放大”的惩罚,所以抗噪能力天然更强。
还有一个很多人忽略的点:曼哈顿距离不具备旋转不变性。你旋转坐标系之后,曼哈顿距离会变。这意味着,使用它时,你对特征轴的解释必须是明确的——每个维度代表一种独立且有意义的度量单位,而不是一个可以随意旋转的抽象空间。用生活类比就是:欧氏距离适合“飞行的距离”,曼哈顿距离适合“开车绕行的距离”,两者度量的是不同世界的真实成本。
1.3 距离度量的本质:我们到底在量什么
这两个距离的差别,最终要落到“度量的本质”上。距离不是数学游戏,它是一种代价函数,描述了从一个点到另一个点的“困难程度”。
如果坐标系里每个方向都是自由移动的,而且移动成本按直线累积,那欧氏距离是对的。如果数据表达的是带有约束的路径,比如街道网络、流程节点、用户行为顺序,或者你更关心每一维度独立贡献了多少差异,而不是整体平方后的复合差异,那么曼哈顿距离更贴近直觉。
选错距离会产生什么后果?举个例子,两个用户购买记录向量都是稀疏的,用户 A 买过商品 X,用户 B 没买过。在先做数据标准化的情况下,欧氏距离会把这个“一买一没买”的差异平方处理;如果这个维度方差很小,平方后会放大成一个很大的分量,相当于把这个“缺失”判了重刑。曼哈顿距离则只是累加绝对值,惩罚相对温和。这也就是为什么很多处理稀疏高维数据的人,会主动换成曼哈顿距离。度量的本质,是你选择用哪种规则解释数据差异。
2. 两种距离到底差在哪:四个核心维度拆解
如果只知道公式,那你就还停留在“会算”的层面。真正做算法工程的人,要能说出这四种差异,才能在具体项目里做出正确选择。
2.1 数值差异:同一条线段,两种长度
最容易验证的差异就是数值大小。给定任意两点,曼哈顿距离通常大于等于欧氏距离。比如点 (0, 0) 到点 (3, 4),欧氏距离是 5,曼哈顿距离是 7。从点 (0, 0) 到 (1, 1),欧氏距离约 1.414,曼哈顿距离是 2。
不只是“曼哈顿永远大于等于欧氏”这一个结论,它们之间的比值还有上界。对于二维情况,曼哈顿距离最多是欧氏距离的 sqrt(2) 倍左右。这个比值的意义在于,在不同维度数下,两倍关系不成立,多维时比值上限会随维度增加。在业务上你不需要背下这些不等式,但你要有概念:换距离度量,同一个 KNN 模型里计算出的近邻完全可能不同,模型表现自然也随之波动。
我做模型对比时经常先写一个快速统计脚本,输出两种距离矩阵的差异分布。如果差异普遍在 5% 以内,换不换无所谓;如果差异大,说明数据里有很多维度差值的绝对值特征比较极端,这才值得深挖。
2.2 旋转不变性与特征轴的解释力
欧氏距离最大的隐性优势是旋转不变性。你从 Y 轴旋转 45 度重新表达同一组点,欧氏距离不变,曼哈顿距离直接面目全非。这意味着两件事:
- 如果特征空间本身存在旋转不变性,即坐标轴的选择不影响实际的“相似度”语义,那欧氏距离是你的好伙伴;
- 如果特征轴的物理意义是绝对的、不可旋转的,比如“购买次数”“点击率”“用户停留秒数”,那么曼哈顿距离更符合直觉。
实际项目中遇到一个典型场景:用户行为特征里包含“浏览数”“收藏数”“购买数”,这些维度的单位不同,含义不同,坐标系根本没有旋转不变性。这时候欧氏距离的“旋转不变优雅性质”反而成了一种误导。曼哈顿距离老老实实把每一维的绝对差异加起来,更可解释,更稳健。
2.3 高维空间里的稳定性
高维诅咒是所有距离度量都无法回避的课题。随着维度增加,在高维空间中,点与点的欧氏距离趋向于极端接近,彼此难以区分。这个现象的根源在于:维度升高后,距离计算里累积了大量维度差值,而由于随机分布的特性,这些差值平方的平均值趋于稳定,拉不开点与点的差异。
曼哈顿距离在高维情况下通常比欧氏距离表现得稍好,因为它用绝对值累加,保留了一定维度的差异信号,不会因为平方操作把小的差异磨灭掉。我做过一个实验:100 维随机稀疏向量,用欧氏距离查找最近邻,命中的很多都是噪声点;换成曼哈顿距离,最近邻匹配准确率明显提升。这不是巧合,而是 L1 范数天然更适合非均匀、稀疏、带有零膨胀特征的数据。但我要提醒一下,曼哈顿距离并不能解决所有高维问题,它只是相对不那么容易崩溃。
2.4 对异常值的敏感度:平方放大效应
欧氏距离计算过程中做了平方,所以一个维度上出现的极端差异会被异常放大。比如两个用户,在“购买金额”这一维上,一个 10 元,一个 1000 元,差的绝对值是 990,平方后变成 98 万,直接淹没了其他维度的所有信息。换句话说,欧氏距离对异常值过度敏感,只要有一两个维度离群,它的整体距离就会被绑架。
曼哈顿距离没有平方这一步,它对单个维度的极端值惩罚没有那么重,在含有噪声特征的场景下,距离计算更稳定。这也是为什么有人说 L1 比 L2 更有鲁棒性,本质上是它们的惩罚方式不同。你在做模型时,如果特征清洗做得不好,又不想过多删特征,用曼哈顿距离可以分担一些风险。
3. 典型应用场景:从算法到业务的对应关系
3.1 KNN 与聚类:距离就是“相似度”的翻译器
KNN 本质上完全依赖距离度量来定义邻居。分类任务中,样本点和谁“近”,取决于你用什么尺子量近。特征空间是标准化的连续稠密向量时,欧氏距离是默认安全牌;但如果你处理的是文本 TF-IDF 特征、高维稀疏用户行为向量,或者有明显噪声的数据,曼哈顿距离往往更合适。我在一个文本分类 Demo 里反复试过,TF-IDF 特征用曼哈顿距离比欧氏距离的准确率高好几个百分点,原因就是 TF-IDF 的维度稀疏且数值分布偏斜,欧氏距离在这种分布下会过度放大高频词的差异。
聚类里更典型。K-Means 用的是欧氏距离,因为它的目标函数是最小化簇内平方误差,这与欧氏距离天然匹配。而 K-Medoids 就是为了规避欧氏距离对噪声点敏感的问题而存在,它常配合曼哈顿距离使用。为什么?因为曼哈顿距离对离群点不那么敏感,中位数比均值更抗噪,两者组合后,聚类结果不会因为一两个极端点被拉得七零八落。如果你的业务数据里注定有脏数据、极端值,而且你又不想做太多清洗,先考虑曼哈顿距离搭配 K-Medoids 是可行路径。
3.2 路径规划与网格世界:要的就是“绕路成本”
这个问题在路径搜索、游戏 AI 和机器人导航中极其突出。一个机器人从格子 (0,0) 走到格子 (5,5),在允许对角移动的开放空间里,欧氏距离是合理参考;但如果地图是四方向移动的网格世界,比如经典迷宫、棋盘、城市街区路网,那实际移动走的就是曼哈顿距离。
很多 Dijkstra 和 A* 算法的最佳启发函数,在网格地图里就是曼哈顿距离,因为它是可采纳的启发函数,不会高估剩余代价。你用一个欧氏距离做网格地图的 A* 启发,它会低估实际代价,导致节点扩展数量剧增、搜索变慢;用曼哈顿距离则恰好贴合真实移动约束,既快又准。这个点我在写一个模拟路径规划的 Demo 时体会很深:同样的地图,启发函数换成曼哈顿距离,寻路时间直接少了近一半。
3.3 推荐系统与行为相似度:别拿飞行距离算出租车里程
做推荐系统时,用户间的相似度计算有很多种做法,除了余弦相似度,基于距离的方法也常用。但这里最容易被忽视的就是:用户行为数据大多是计数型稀疏数据,分布极度不均。有人在两个用户向量的欧氏距离里,因为某一维的悬殊差异,把真正兴趣接近的用户全部排到了后面。如果改用曼哈顿距离,每一维差异独立累加,至少不会因为单个极端值导致整个相似度崩溃。
我印象很深的一个案例:某次做商品推荐的聚类划分,对比了欧氏距离和曼哈顿距离下的用户分群结果。欧氏距离分出来的群,肉眼可见地被“高消费用户”的离群行为主导;而曼哈顿距离分出来的群,各群内的品类偏好分布更均衡,后续投放到各群的推荐点击率也明显更好。这不代表曼哈顿永远更好,但它说明,在真实业务数据中,距离度量的选择必须跟着数据分布走,而不是跟着默认习惯走。
4. 实操指南:什么时候用哪种距离,以及怎么快速验证
很多人在实际项目里不知道怎么下手。这里给出一条我验证过多次的路线,核心思想是:先理解数据的代价模型,再用小实验验证,最后才定下来。
4.1 第一个前提任务:特征标准化
不管你选哪种距离,不标准化就想直接比较距离,都是给结果注入随机噪音。典型例子:一个特征量级是 0 到 1,另一个特征量级是 1000 到 100000,如果直接计算距离,后者几乎完全支配了距离值,前者的全部信息被忽略。标准化后的欧氏距离,相当于把每个维度归一到相同的尺度,才谈得上“加权平均”式的综合差异。曼哈顿距离也一样,不做标准化,等于默认不同维度单位之间有固定的换算关系,这基本不成立。
常见的做法是 Z-Score 标准化(均值 0,方差 1)或 Min-Max 缩放(映射到 [0,1])。对于稀疏数据,更推荐先做 Min-Max 或者针对非零值做标准化,具体要看业务。不要迷信一个标准走天下,特征分布不同,标准化方式要有取舍。
4.2 快速判断的四步流程
第一步,问一个问题:在这个场景里,“两个点的差异”是按直线飞行算,还是按沿轴移动的累积代价算?
如果是推荐、文本、稀疏行为计数场景,答案偏向后者,直接优先试曼哈顿距离。如果是连续物理量,如位置坐标、温度、压力,做回归或分类,优先试欧氏距离。
第二步,看数据是否稀疏。高维稀疏特征优先考虑曼哈顿距离。TF-IDF、用户-商品矩阵、基因表达矩阵都是典型的高维稀疏数据。
第三步,看异常值是否明显。如果特征中存在明显的长尾分布,又不想做太多清洗,曼哈顿距离可以降低异常值的影响。
第四步,千万不要停留在“我觉得”。直接用小规模数据跑一次对比实验,选 KNN 或者你正在用的聚类算法,分别以欧氏距离、曼哈顿距离、余弦相似度作为度量,看交叉验证得分。这个实验花费的时间不超过一个小时,但它能终结所有无意义的争论。
4.3 一个可复现的小实验案例
这里分享一个我在某次内部技术分享里用过的模拟案例。数据集是某某项目的用户行为特征,800 个样本,每个样本 60 维,记录了某电商场景下用户对 60 个商品类目的浏览、收藏、购买次数,标签是“是否在两周内产生复购”。这是典型的高维稀疏、有重尾分布、包含极端活跃用户的数据。
我做了三个实验配置:
| 配置编号 | 特征处理 | 距离度量 | KNN 交叉验证准确率 |
|---|---|---|---|
| 1 | Min-Max 标准化 | 欧氏距离 | 0.812 |
| 2 | Min-Max 标准化 | 曼哈顿距离 | 0.853 |
| 3 | 不标准化 | 曼哈顿距离 | 0.766 |
第三个配置的准确率下跌,再次验证了“不标准化,一切白搭”。第一个和第二个的差距则说明:在这个稀疏重尾场景下,曼哈顿距离确实更贴合数据特性。后来我把曼哈顿距离用在线上推荐召回里,离线指标提升之外,线上点击表现也更稳定。这类实验非常值得复现,因为它做起来成本极低,却能帮你建立对距离度量的直觉。
4.4 代码实现上的三个细节
使用 numpy 计算两种距离,很多人会犯低级错误。linalg.norm 默认算的是欧氏距离,要算曼哈顿距离可以直接用以上公式逐维绝对差求和,或者用 sklearn 的 DistanceMetric。但要注意批量计算的数值稳定性:如果特征数值特别大(百万级),平方求和会出现溢出风险,建议先把数据做标准化或缩小到合适量纲再算。绝对值累加则相对不容易溢出,但也要注意数据类型用 float64 而不是 int,否则累计结果可能丢失精度。
再有一个细节,就是稀疏矩阵的曼哈顿距离计算不要转成稠密矩阵硬算,那样内存直接爆掉。用 scipy.spatial.distance 里支持稀疏输入的函数,或者自己写一个循环遍历稀疏行求绝对差,速度又快又省内存。我在处理一个 10 万样本 ×1 万维的稀疏矩阵时,稀疏导出的方式比稠密计算快了 20 倍以上,内存占用也完全不是一个量级。
5. 常见问题与避坑经验
5.1 换距离后性能不升反降,到底哪里出了问题
有不少人拿到我的建议后,回去把模型距离从欧氏换成曼哈顿,结果发现指标反而降了。常见原因有三个。
第一,特征没有做标准化,或者标准化方式不匹配数据分布。第二,数据本身是稠密连续且所有维度都有物理意义的,这种情况下曼哈顿距离的“逐维绝对差累加”反而丢弃了维度间相关结构的信息,损失了整体性。第三,样本量太小,距离度量的差异被噪声主导,换不换其实都一样,分数波动是随机的。
正确的排查思路是:先做标准化,再对比两种距离上的误差分布。如果欧氏距离本身已经很好,说明数据连续性和空间各向同性都较强,不必为了用而用。
5.2 高维数据下,曼哈顿距离也不是万能药
在高维空间,曼哈顿距离比欧氏距离更抗退化,但它依然会退化。当维度数几百上千,所有样本间距离都趋于接近时,任何基于距离的模型都难逃诅咒。网上有说法“高维一定用曼哈顿”,这个表述太绝对。在实践中我更推荐:先尝试降维(PCA、特征选择),再做距离度量,效果好过单纯换度量方式。
我曾经在一个 3000 维的特征集上试着比较欧氏和曼哈顿,两者效果都不好,后来用特征选择降到 150 维再计算欧氏距离,效果反超了原先的曼哈顿结果。这说明数据维度过高时,问题不只出在度量方式,而是特征本身带了太多噪音。距离度量的选择,要放在特征工程整个链路里去思考,不要孤立地换尺子。
5.3 余弦相似度和这两种距离怎么权衡
做文本或推荐时,很多人还会纠结:是不是应该用余弦相似度而不是距离?我的经验是:当你关心的是“方向差异”而不是“幅值差异”,比如文本中一篇长文章和一篇短文章,长度差异不影响主题相关度判断,那余弦相似度更有优势。当你关心的是实际行为差异的“强度”,比如用户购买次数的多少就直接代表活跃度的强弱,那距离类度量更合适。
有时还会混合用。例如在用户向量先做 L2 归一化之后,欧氏距离和余弦相似度的排序关系是单调一致的,所以用欧氏距离和用余弦相似度差别不大。很多人不知道这个小 trick:先归一化再算欧氏距离,可以起到类似余弦相似度的效果,同时对稀疏值的处理更友好。这个技巧在处理用户行为数据时经常能省很多事。
5.4 曼哈顿和欧氏之外:切比雪夫距离、马氏距离什么时候用
切比雪夫距离是各维度差值绝对值的最大值,它适合描述的是“最大一步代价”,比如国际象棋中国王走一步能覆盖周围八个格子,它移动的步数就是切比雪夫距离。如果业务场景中单一维度上的最大差异才是关键代价,比如服务器多个监控指标中只要有一个异常严重就要告警,那么切比雪夫距离可能比曼哈顿更适合。
马氏距离则更进一步,它考虑了特征之间的相关性,在协方差矩阵存在明显结构时,马氏距离能正确衡量“在多维相关分布中的距离”。但它计算成本高,样本量少时协方差估计不稳定。我的建议是:先掌握好欧氏和曼哈顿这两种基础度量,等遇到相关特征明显的数据时,再研究马氏距离作为进阶延伸。不要一开始就把模型搞复杂,基础尺子用好了,已经能解决大多数问题。
最后分享一个实际工作中的体会
距离度量这个事,看似基础,实则是整个机器学习流程里最容易被低估的一个设计决策。我个人现在的习惯是:接到一个新任务时,先花十几分钟把数据分布、稀疏度、异常值情况摸一遍,再选择默认距离,然后用小实验快速验证。比起直接调模型参数,这一步的性价比高得多。正是因为之前吃过“无脑欧氏距离”的亏,现在才格外看重这种基础选择。如果你也在做 KNN、聚类或者推荐相关的项目,建议你拿手头数据试试曼哈顿距离,对照一下实验指标,结果可能比预期更惊喜。那组对比数据的差异,就藏在你看似平常的距离公式里。