與應用場景)
距離度量是很多算法繞不開的基礎環(huán)節(jié)做KNN、K-Means、層次聚類、推薦系統(tǒng)、向量檢索甚至評估兩個樣本之間的相似性本質上都是在算“距離”。我過去在項目里用過不少現(xiàn)成的庫比如scikit-learn里的pairwise_distances幾行代碼就能批量算完但后來發(fā)現(xiàn)如果只是無腦調接口不理解每一種距離到底在衡量什么很容易在特征選型、結果調優(yōu)的時候吃暗虧。所以這次打算把Python里最常用的七種距離度量方法一次性講透。每一種我都會給出公式層面的直觀理解、可直接運行的Python實現(xiàn)、適合的業(yè)務場景以及我實測下來踩過的坑。這七種分別是歐氏距離、曼哈頓距離、切比雪夫距離、閔可夫斯基距離、余弦距離、漢明距離、杰卡德距離。內容偏基礎但基礎不代表不重要恰恰是這些底層度量方式決定了上游算法最終能跑出什么效果。1. 距離度量方法的整體設計與選型思路1.1 為什么需要關注距離度量方式很多入門的朋友對距離度量的理解停留在“就是兩點之間算個直線長度”比如在二維平面上兩個坐標點(x1, y1)和(x2, y2)之間的距離用勾股定理就能算出來。這個直覺沒有錯歐氏距離確實是應用最廣的一種。但現(xiàn)實中的數(shù)據(jù)往往不是簡單的二維平面坐標它可能是用戶在電商平臺上的行為向量、商品評論的文本向量、圖片經過卷積網(wǎng)絡提取出的高維特征甚至是不定長的集合數(shù)據(jù)。不同的數(shù)據(jù)形態(tài)對應著不同的“距離”定義方式。我在做推薦系統(tǒng)的時候遇到過一個問題用歐氏距離去度量兩個用戶的相似度結果和業(yè)務預期完全對不上。后來仔細檢查發(fā)現(xiàn)用戶行為向量的維度之間量綱差異極大有的維度是點擊次數(shù)數(shù)值能到幾千有的維度是是否購買取值只有0或1。這種情況下歐氏距離幾乎被數(shù)值大的維度主導整個度量就失真了。這就是為什么理解距離度量不能只停留在“會調用np.linalg.norm”這個層面而是要知道每個距離公式背后的幾何意義、對數(shù)據(jù)形態(tài)的要求、以及在不同業(yè)務場景中的適配性。1.2 七種距離度量的分類與場景定位我們可以先把這七種距離做一個粗略的分類便于后續(xù)逐個展開時心里有個全局框架?;谧鴺它c幾何位置的歐氏距離、曼哈頓距離、切比雪夫距離、閔可夫斯基距離。它們適用于特征向量已經是連續(xù)型數(shù)值、且各維度具有明確物理意義的場景。這類距離是“從A點到B點怎么走”的幾何模型?;诜较蛞恢滦缘挠嘞揖嚯x。它主要衡量兩個向量在方向上的相似程度對向量的絕對大小不敏感常用于文本向量化的相似度計算?;陔x散分值或集合視角的漢明距離和杰卡德距離。漢明距離面向等長的離散序列統(tǒng)計位置上的差異數(shù)杰卡德距離面向集合數(shù)據(jù)衡量交集與并集的比例關系。在實際項目中我習慣先問自己三個問題數(shù)據(jù)是連續(xù)型還是離散型特征是否有量綱差異業(yè)務上關心的核心是“數(shù)值接近”還是“模式一致”這三個問題基本能鎖定該用哪一類距離。比如用戶畫像標簽這種離散特征我會優(yōu)先考慮杰卡德距離文本語義相似度優(yōu)先余弦距離而單純的數(shù)值型特征往往會從歐氏或曼哈頓里選。1.3 選型時的核心原則距離度量的選擇不是越復雜越好而是要匹配數(shù)據(jù)形態(tài)和業(yè)務目標。我在項目里總結出幾個原則供大家參考。量綱統(tǒng)一優(yōu)先于距離公式選擇。如果特征包含年齡、收入、點擊次數(shù)這種量綱差異很大的字段優(yōu)先做標準化比如StandardScaler否則任何基于幾何位置的距離都會失真。高維數(shù)據(jù)慎用歐氏距離。當特征維度超過幾十維之后樣本間的歐氏距離會逐漸趨于平均化區(qū)分度下降這也是“維度災難”的一種體現(xiàn)。這時候余弦距離或漢明距離往往更穩(wěn)健。業(yè)務語義優(yōu)先于數(shù)學幾何意義。比如計算用戶相似度兩個用戶的購買向量分別是[1, 0, 0]和[50, 0, 0]歐氏距離很大但業(yè)務上這兩個用戶都只買了一個商品余弦距離會判定為完全相似在這個場景下余弦往往更符合“偏好一致”的語義。不考慮效率只談效果也是不行的。在實際工程里幾千萬條樣本兩兩算距離時間復雜度是O(n2)這時候距離公式的計算成本會成為瓶頸后面我會專門講性能優(yōu)化的經驗。2. 歐氏距離與曼哈頓距離2.1 歐氏距離最常用但不一定最合適歐氏距離Euclidean Distance的幾何意義是空間中兩點的直線距離。二維平面上兩點(x1, y1)和(x2, y2)的歐氏距離公式是d sqrt((x1 - x2)^2 (y1 - y2)^2)推廣到n維空間就是每個維度差值的平方和再開根號d sqrt(sum((x_i - y_i)^2))用Python實現(xiàn)非常直接。我這里給出一個原生Python版本如果你在面試中被問到手寫距離函數(shù)這個寫法夠用生產環(huán)境直接用NumPy向量化計算就好。import math def euclidean_distance(a, b): 計算兩個n維向量的歐氏距離a和b是等長的可迭代對象 if len(a) ! len(b): raise ValueError(兩個向量的維度必須一致) return math.sqrt(sum((x - y) ** 2 for x, y in zip(a, b)))用NumPy更優(yōu)雅而且運算速度會快不少import numpy as np def euclidean_distance_np(a, b): return np.sqrt(np.sum((np.array(a) - np.array(b)) ** 2))歐氏距離是最直觀的“直線距離”在數(shù)據(jù)維度不高、各個特征已經做過標準化的情況下它的表現(xiàn)往往不錯。我之前做過一個鳶尾花分類的演示項目直接用花瓣長度、花瓣寬度這種量綱相近的特征做KNN歐氏距離就夠用。但如果特征量綱差異很大比如一個特征是0到1之間的概率值另一個特征是0到10000之間的收入金額歐氏距離就容易被“大數(shù)”帶跑偏。這種情況下有兩個思路第一對特征做標準化第二換成曼哈頓距離試試它對異常值的敏感度更低。這里有一個我實際遇到過的問題在高維稀疏向量上使用歐氏距離效果很差。比如文本的TF-IDF向量動輒上萬維但絕大多數(shù)維度是0歐氏距離會把大量的“0-0相等”也納入計算結果是所有樣本之間的距離都差不多區(qū)分度很低。這時候更適合余弦距離后面會講到。2.2 曼哈頓距離城市街區(qū)的走法曼哈頓距離Manhattan Distance的命名來源于美國曼哈頓的街區(qū)布局那里街道是方格狀的從一個路口到另一個路口只能橫著走或豎著走不能斜穿。它的數(shù)學形式是各維度絕對值差之和d sum(|x_i - y_i|)Python實現(xiàn)也很簡單def manhattan_distance(a, b): if len(a) ! len(b): raise ValueError(兩個向量的維度必須一致) return sum(abs(x - y) for x, y in zip(a, b))NumPy版本def manhattan_distance_np(a, b): return np.sum(np.abs(np.array(a) - np.array(b)))曼哈頓距離和歐氏距離的區(qū)別在于它對每一個維度的差異都賦予相同的線性權重差值不會被平方放大。這個特性讓它對離群值沒那么敏感。比如某個維度的某個樣本取值異常大歐氏距離會因為平方操作把這個異常放大而曼哈頓距離只是增加了該維度上的一個絕對差值項影響相對有限。在實際業(yè)務里曼哈頓距離經常被用在路徑規(guī)劃、網(wǎng)格場景的相似度計算當中。比如外賣配送中估算兩個地點的距離因為道路是網(wǎng)格化的直線距離反而不符合實際。又比如在L1正則化的邏輯里也是利用了曼哈頓式“絕對差累加”的特性來促使稀疏解。我在做KNN時也做過對比實驗當特征中存在噪聲較大的離群點曼哈頓距離的預測穩(wěn)定性普遍優(yōu)于歐氏距離。2.3 兩種距離的對比與使用建議用一張表格做個直觀對比對比維度歐氏距離曼哈頓距離幾何含義兩點間的直線距離網(wǎng)格路徑的折線距離數(shù)學形式差值平方和再開方絕對差之和對異常值的敏感度較高平方放大較低線性累積高維稀疏數(shù)據(jù)表現(xiàn)較差比歐氏稍好但仍不理想典型應用KNN、K-Means、圖像特征路徑規(guī)劃、稀疏特征、L1場景我的建議是如果特征經過了標準化且維度不是特別高優(yōu)先用歐氏距離因為它的幾何直覺強很多算法的默認實現(xiàn)也基于它。如果數(shù)據(jù)里存在明顯離群點或者特征維度較高但還沒到稀疏的程度可以先試曼哈頓距離。還有一種常用做法是把兩者結合起來用也就是后面要講的閔可夫斯基距離通過調節(jié)參數(shù)p來在歐氏和曼哈頓之間切換。3. 切比雪夫距離與閔可夫斯基距離3.1 切比雪夫距離象棋里國王的走法切比雪夫距離Chebyshev Distance這個名字對初學者來說有些陌生但如果解釋成“國際象棋中國王從一個格子走到另一個格子需要的最少步數(shù)”一下子就明白了。國王可以向任意方向移動一格所以距離等于兩個坐標值中差值最大的那個d max(|x_i - y_i|)Python代碼def chebyshev_distance(a, b): if len(a) ! len(b): raise ValueError(兩個向量的維度必須一致) return max(abs(x - y) for x, y in zip(a, b))NumPy版本def chebyshev_distance_np(a, b): return np.max(np.abs(np.array(a) - np.array(b)))切比雪夫距離強調的是“最突出的那個維度差異”其他維度的差異被忽略了。這個特性讓它適合處理那些只有“最大偏差”才有意義的場景。比如兩個機器人坐標系之間的同步偏差控制只要任何一個方向上的偏差超過閾值就需要校正這時候切比雪夫距離就很合適。有一個容易混淆的點需要注意切比雪夫距離不是簡單地在所有維度差異里取最大值而是先用絕對值算出每個維度的差異再在差異之間取最大。理解了這個你在用的時候就會清楚它和歐氏距離、曼哈頓距離的本質區(qū)別——歐氏算的是“總體的接近程度”曼哈頓算的是“路徑總代價”切比雪夫算的是“最壞的一步是否可控”。3.2 閔可夫斯基距離一個公式統(tǒng)一多種距離閔可夫斯基距離Minkowski Distance是一個更通用的形式它有一個參數(shù)p來決定距離的具體形態(tài)d (sum(|x_i - y_i|^p))^(1/p)當p1時它就是曼哈頓距離當p2時它就是歐氏距離當p趨向正無窮時它會趨近于切比雪夫距離。所以閔可夫斯基距離可以看作是一個“可調節(jié)的距離度量家族”通過改變p值來適配不同的數(shù)據(jù)分布。Python實現(xiàn)def minkowski_distance(a, b, p): if len(a) ! len(b): raise ValueError(兩個向量的維度必須一致) if p 1: raise ValueError(p值必須大于等于1否則不滿足三角不等式) return sum(abs(x - y) ** p for x, y in zip(a, b)) ** (1 / p)我用一個簡單的例子來驗證——兩個點(1, 2)和(4, 6)歐氏距離sqrt(3^2 4^2) 5曼哈頓距離3 4 7切比雪夫距離max(3, 4) 4p3的閔可夫斯基距離(3^3 4^3)^(1/3) 91^(1/3) ≈ 4.497可以看到隨著p增大距離值在歐氏和切比雪夫之間變化。這個公式的價值不在于說“我多記了一種距離”而在于它提供了一種調參思路你可以在同一個算法框架下用不同的p值做交叉驗證找到最適合當前數(shù)據(jù)分布的距離度量。我在做KNN調參時就用過這個思路把p作為一個超參喂給網(wǎng)格搜索讓數(shù)據(jù)自己決定該偏向歐氏還是曼哈頓。3.3 p值選擇的實踐經驗閔可夫斯基距離里的p值不是一個隨便填的數(shù)字它背后有數(shù)據(jù)分布的語義。p越小距離對各個維度的差異越敏感所有維度都會被“平均地”計入p越大距離越接近“由最大差異主導”。在實際項目中我的做法通常是先保證特征標準化否則p值再怎么調也救不了量綱問題。用網(wǎng)格搜索或隨機搜索把p值也納入超參范圍比如從1到5之間的步長0.5逐步嘗試。觀察不同p值下模型在驗證集上的表現(xiàn)變化。如果p1明顯優(yōu)于p2說明數(shù)據(jù)中異常值較多曼哈頓式的魯棒性更值錢如果p2更好說明數(shù)據(jù)的整體幾何結構比較規(guī)整。需要注意一個數(shù)學上的約束p值必須大于等于1。當p小于1時閔可夫斯基距離不再滿足三角不等式也就不是嚴格意義上的“距離度量”在一些基于距離的算法中可能會導致奇怪的結果。這是我早期踩過的坑當時為了強行放大差異把p設成0.5結果KMeans聚類結果完全不可解釋后來查資料才反應過來是距離公理的問題。4. 余弦相似度與漢明距離4.1 余弦相似度關注方向而非大小余弦相似度衡量的是兩個向量在方向上的“重合程度”計算的是兩個向量夾角的余弦值cos(θ) (A·B) / (|A| * |B|)余弦值越接近1夾角越小向量方向越一致越接近0夾角越大越接近-1方向越相反。在Python中把余弦值轉換為“距離”時一般用1 - cosine_similarity稱為余弦距離。def cosine_similarity(a, b): dot_product sum(x * y for x, y in zip(a, b)) norm_a math.sqrt(sum(x ** 2 for x in a)) norm_b math.sqrt(sum(y ** 2 for y in b)) if norm_a 0 or norm_b 0: raise ValueError(零向量無法計算余弦相似度) return dot_product / (norm_a * norm_b) def cosine_distance(a, b): return 1 - cosine_similarity(a, b)NumPy的向量化實現(xiàn)更簡潔而且你可以直接用from sklearn.metrics.pairwise import cosine_similarity底層已經幫你做了大量優(yōu)化。余弦相似度最大的優(yōu)勢是對“尺度不敏感”。比如用戶的購物向量[1, 0, 0]和[10, 0, 0]歐氏距離會認為兩者差異巨大但余弦相似度會認為兩者方向完全一樣都是只對第一個商品有偏好。這個特性在文本場景里尤其好用文檔長度不同詞頻絕對數(shù)值可能差很多倍但語義傾向可能很接近TF-IDF向量化之后用余弦相似度就能比較公平地度量。不過我踩過一個坑余弦相似度對零向量的處理需要單獨判斷。如果某個用戶沒有產生任何行為向量全為0余弦公式里分母為0會直接報錯。工程上需要給這種“零向量”一個默認相似度比如0或者在預處理階段把零向量過濾掉。4.2 漢明距離數(shù)一數(shù)有幾個位置不一樣漢明距離Hamming Distance適用于兩個等長序列統(tǒng)計它們在相同位置上不同元素的數(shù)量。定義很樸素d count(x_i ! y_i)它最早用于通信中的差錯檢測后來被廣泛用于字符串相似度、基因序列比對、二值特征向量的比較。Python實現(xiàn)def hamming_distance(a, b): if len(a) ! len(b): raise ValueError(兩個序列的長度必須一致) return sum(x ! y for x, y in zip(a, b))漢明距離也可以直接用位運算優(yōu)化。如果兩個等長的二進制向量用0/1表示異或運算可以直接統(tǒng)計差異位def hamming_distance_binary(a, b): # 這里假設a和b是等長的0/1列表 xor [x ^ y for x, y in zip(a, b)] return sum(xor)漢明距離更適合處理“離散取值”的數(shù)據(jù)比如用戶是否安裝某類App的0/1標簽、拼寫糾錯中單詞字符的差異數(shù)。在二進制特征上漢明距離的語義非常清晰兩個用戶共同安裝和共同未安裝的維度都不重要重要的是“有差異”的維度有多少。需要特別注意的是漢明距離要求序列等長。如果兩個字符串長度不一致就需要先做對齊或者切換到編輯距離Levenshtein Distance。另外漢明距離對每個位置一視同仁不考慮位置之間的關聯(lián)性所以它適合那些“每個位置獨立且有明確語義”的特征。4.3 場景區(qū)分什么時候用余弦什么時候用漢明這兩類距離在很多項目里容易混淆我分享一個自己的判斷標準如果特征是連續(xù)數(shù)值向量比如TF-IDF、詞向量均值池化、深度學習embedding優(yōu)先用余弦相似度。因為這些向量本身帶有“方向”語義而且通常維度高歐氏距離的維度災難問題會比較嚴重。如果特征是等長的離散編碼尤其是0/1二值特征優(yōu)先用漢明距離。比如用戶是否安裝某類應用、是否具備某些標簽這種情況下位置的差異本身就是業(yè)務差異漢明距離解釋性強。如果特征是集合形式的數(shù)據(jù)比如用戶購買了哪些商品、文檔包含哪些關鍵詞那更合適的是杰卡德距離這正是下一個要講的內容。我自己在做一個App用戶分群項目時用漢明距離對安裝列表特征做聚類效果顯著優(yōu)于歐氏距離——原因也很簡單安裝列表是0/1矩陣歐氏距離會平方放大差異相當于給“同時未安裝”的維度也賦予了權重而這部分權重在業(yè)務上沒有意義。5. 杰卡德距離與整體對比總結5.1 杰卡德距離集合視角下的相似度杰卡德相似度Jaccard Similarity衡量兩個集合的交集大小與并集大小的比例J(A, B) |A ∩ B| / |A ∪ B|對應的杰卡德距離為d_J(A, B) 1 - J(A, B)Python實現(xiàn)可以用原生的set操作def jaccard_similarity(a, b): set_a set(a) set_b set(b) intersection len(set_a set_b) union len(set_a | set_b) if union 0: return 1.0 # 兩個空集合認為是相似的 return intersection / union def jaccard_distance(a, b): return 1 - jaccard_similarity(a, b)杰卡德距離的關鍵在于它只看“是否出現(xiàn)”不看出現(xiàn)次數(shù)的多少。比如用戶A購買了商品集合{牛奶, 面包, 雞蛋}用戶B購買了{牛奶, 可樂, 薯片}兩個集合的交集是{牛奶}并集是五個商品杰卡德相似度為1/5 0.2距離為0.8。這個視角天然適合標簽數(shù)據(jù)和集合型數(shù)據(jù)。我實際業(yè)務中用杰卡德距離最多的場景是“用戶興趣相似度”計算?;ヂ?lián)網(wǎng)產品里用戶畫像經常被表示成一組標簽集合如果用歐氏距離去處理標簽編碼后的稀疏向量效果很差但用集合直接求交并比就很干凈。另一個典型場景是推薦系統(tǒng)中的物品相似度比如同時被很多人購買過的商品列表用杰卡德系數(shù)可以找出真正的關聯(lián)商品。5.2 七種距離的Python實現(xiàn)匯總上面每種距離已經給出了具體函數(shù)這里把它們放到一起方便在項目里直接復制使用。我習慣把這一組函數(shù)封裝成一個模塊方便不同項目復用import math import numpy as np def euclidean_distance(a, b): return math.sqrt(sum((x - y) ** 2 for x, y in zip(a, b))) def manhattan_distance(a, b): return sum(abs(x - y) for x, y in zip(a, b)) def chebyshev_distance(a, b): return max(abs(x - y) for x, y in zip(a, b)) def minkowski_distance(a, b, p): if p 1: raise ValueError(p值必須大于等于1) return sum(abs(x - y) ** p for x, y in zip(a, b)) ** (1 / p) def cosine_distance(a, b): dot_product sum(x * y for x, y in zip(a, b)) norm_a math.sqrt(sum(x ** 2 for x in a)) norm_b math.sqrt(sum(y ** 2 for y in b)) if norm_a 0 or norm_b 0: return 1.0 return 1 - dot_product / (norm_a * norm_b) def hamming_distance(a, b): if len(a) ! len(b): raise ValueError(兩個序列的長度必須一致) return sum(x ! y for x, y in zip(a, b)) def jaccard_distance(a, b): set_a set(a) set_b set(b) union set_a | set_b if len(union) 0: return 0.0 intersection set_a set_b return 1 - len(intersection) / len(union)5.3 七種距離的整體橫向對比用一個表格把核心差異列出來方便查閱距離名稱核心思想適用數(shù)據(jù)形態(tài)對量綱敏感度對異常值敏感度歐氏距離直線距離連續(xù)數(shù)值向量高高曼哈頓距離折線路徑和連續(xù)數(shù)值向量高中切比雪夫距離最大差異連續(xù)數(shù)值向量高中閔可夫斯基距離可調p值的廣義距離連續(xù)數(shù)值向量高隨p變化余弦距離方向夾角高維向量、文本低低漢明距離等長序列位置差異等長離散序列、0/1特征不適用低杰卡德距離集合交并比集合、標簽、離散項不適用低這張表在實際項目中幫我節(jié)省了大量對比時間。遇到一個新任務先看數(shù)據(jù)結構再查這張表基本就知道從哪里下手。另外補充一個容易被忽略的細節(jié)在scikit-learn的多個聚類和KNN算法里距離參數(shù)可以直接通過字符串指定比如metriceuclidean、metricmanhattan、metriccosine、metrichamming、metricjaccard而閔可夫斯基距離需要額外傳p值。官方文檔里還有更多距離可選但本質逃不開上面這幾種原始思路。6. 常見問題與實測經驗記錄6.1 要不要先對特征做標準化答案是只要使用幾何類距離歐氏、曼哈頓、切比雪夫、閔可夫斯基就必須做標準化。這不是一個可選項而是必須項。我自己吃過虧用未標準化的一堆特征跑KNN效果極度依賴量綱大的維度換了個排序方式結果完全變了個樣。標準化的方式根據(jù)業(yè)務特性來選如果數(shù)據(jù)近似正態(tài)分布用StandardScaler如果數(shù)據(jù)存在較多離群值用RobustScaler它基于中位數(shù)和四分位距對離群值更魯棒如果特征是稀疏的比如TF-IDF通常不進行標準化而是直接用余弦距離。6.2 高維數(shù)據(jù)到底選哪種距離高維數(shù)據(jù)下歐氏距離會趨近失效這已經被很多人驗證過。我自己做過一個實驗在50維的隨機數(shù)據(jù)上計算樣本對之間的歐氏距離發(fā)現(xiàn)距離值分布非常集中區(qū)分度極低。這時候建議改為余弦距離或漢明距離。但余弦距離也有自身的盲區(qū)它對向量的絕對大小完全不敏感。在有些場景里大小恰恰是業(yè)務信號比如用戶活躍度相差懸殊兩個用戶行為方向一致但活躍度差了100倍余弦距離會判定為完全相似這種結果可能不符合預期。更嚴謹?shù)淖龇ㄊ墙Y合多種特征準備一個綜合的相似度評分體系而不是指望單一距離解決所有問題。6.3 計算性能優(yōu)化經驗距離計算在兩兩比對場景下很容易變成性能瓶頸。比如十萬元的用戶向量兩兩計算就是百億級別的運算逐層for循環(huán)會慢到懷疑人生。我的優(yōu)化經驗按優(yōu)先級排列如下。第一用向量化計算替代Python循環(huán)。NumPy的廣播機制允許你一次算完一整批距離。比如計算一個矩陣中所有樣本兩兩之間的歐氏距離用scipy.spatial.distance.cdist(X, X, metriceuclidean)效率極高。第二利用矩陣運算加速。歐氏距離有一個等價展開公式d^2 |A|^2 |B|^2 - 2AB^T用NumPy矩陣乘法一步到位比雙重循環(huán)快幾個數(shù)量級。這也是很多向量檢索庫的底層優(yōu)化思路。第三大數(shù)據(jù)量下用近似索引。幾十萬上百萬級別的高維向量要實時檢索最近鄰暴力計算根本扛不住這時候應該用近似最近鄰庫比如faiss或hnswlib它們內部做了索引和剪枝檢索速度能提升幾個量級。工程上不要為了“純Python實現(xiàn)”而放棄性能選擇合適的工具才是專業(yè)做法。6.4 我對距離度量這件事的整體體會做了這么多項目我的感受是距離度量雖然只是算法鏈路里的一小步但它決定了模型看待數(shù)據(jù)的方式。選錯距離后續(xù)調參、加特征、換模型都很難挽救選對距離很多問題在數(shù)據(jù)處理階段就已經有了高區(qū)分度的表示。最后再分享一個小技巧在方案驗證階段可以同時用幾種距離度量跑同一套算法把距離作為超參網(wǎng)格搜索的一部分。整個過程不需要太多額外代碼但能讓你快速了解當前數(shù)據(jù)的“距離偏好”長期下來會形成一種直覺看到一份數(shù)據(jù)就能大致判斷該用哪種距離。這種經驗沒法速成但通過這篇文章里的實現(xiàn)和對比表格你應該能少走不少彎路。