cosine_sim(A, B) = (A · B) / (||A|| * ||B||)

如果你將向量A和B歸一化為單位向量A’和B’,計算它們的點積,那么:
A' · B' = cosine_sim(A, B)
此時,點積(Dot Product)就等于余弦相似度。

核心影響:歸一化讓相似度計算從關注"方向和強度"變成了只關注"純方向"。

不歸一化 歸一化后
關注點 方向 + 強度(總量) 純方向(比例、形態)
模長作用 是關鍵因素,模長大的向量占主導 被完全消除,所有向量平等
好比 比較兩首歌的絕對音量音色 只比較兩首歌的音色,把音量調成一致

理解了這一點,我們就可以通過案例和代碼來看看如何選擇了。

二、案例一:何時必須歸一化?——關注"形態"而非"總量"

場景:文檔相似度計算

假設你有兩篇文檔:

我們用TF-IDF模型將它們轉化為向量。

import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer

# 示例文檔
documents = [
    "machine learning deep neural network artificial intelligence",  # 長文檔A
    "ai artificial intelligence"  # 短文檔B
]

# 計算TF-IDF向量
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(documents)

# 轉換為稠密數組以便演示
vectors = tfidf_matrix.toarray()

print("原始TF-IDF向量:")
print("文檔A:", vectors[0])
print("文檔B:", vectors[1])
print()

# 計算模長
norm_a = np.linalg.norm(vectors[0])
norm_b = np.linalg.norm(vectors[1])
print(f"文檔A模長: {norm_a:.4f}")
print(f"文檔B模長: {norm_b:.4f}")
print()

# 計算未歸一化的余弦相似度
dot_product = np.dot(vectors[0], vectors[1])
cosine_sim_unnormalized = dot_product / (norm_a * norm_b)
print(f"未歸一化余弦相似度: {cosine_sim_unnormalized:.4f}")

# 歸一化向量
normalized_a = vectors[0] / norm_a
normalized_b = vectors[1] / norm_b

print("\n歸一化后的向量:")
print("文檔A:", normalized_a)
print("文檔B:", normalized_b)
print()

# 計算歸一化后的余弦相似度(即點積)
cosine_sim_normalized = np.dot(normalized_a, normalized_b)
print(f"歸一化后余弦相似度: {cosine_sim_normalized:.4f}")

# 驗證:直接使用余弦相似度公式應與歸一化后點積結果一致
cosine_sim_direct = dot_product / (np.linalg.norm(vectors[0]) * np.linalg.norm(vectors[1]))
print(f"直接計算余弦相似度: {cosine_sim_direct:.4f}")

? 結論:在文本處理、圖像顏色直方圖比較、用戶興趣偏好分析等場景中,模長(文檔長度、圖片亮度、用戶活躍度)是干擾噪聲,我們真正關心的是分布形態。此時,必須歸一化。

三、案例二:何時不用歸一化?——當"總量"本身就是信息

場景:推薦系統中的用戶評分預測

假設在一個電影評分系統(1-5分)中,有兩個用戶:

# 用戶評分向量示例
user_a_ratings = np.array([5, 3, 2, 1])  # 苛刻用戶,但對某部電影給出5星
user_b_ratings = np.array([5, 4, 4, 5])  # 寬容用戶,對同一部電影也給出5星

print("用戶評分向量:")
print("用戶A(苛刻):", user_a_ratings)
print("用戶B(寬容):", user_b_ratings)
print()

# 計算模長
norm_a = np.linalg.norm(user_a_ratings)
norm_b = np.linalg.norm(user_b_ratings)
print(f"用戶A評分向量模長: {norm_a:.4f}")
print(f"用戶B評分向量模長: {norm_b:.4f}")
print()

# 計算未歸一化的點積相似度
dot_product_unnormalized = np.dot(user_a_ratings, user_b_ratings)
print(f"未歸一化點積相似度: {dot_product_unnormalized:.4f}")

# 計算未歸一化的余弦相似度
cosine_sim_unnormalized = dot_product_unnormalized / (norm_a * norm_b)
print(f"未歸一化余弦相似度: {cosine_sim_unnormalized:.4f}")
print()

# 歸一化向量
normalized_a = user_a_ratings / norm_a
normalized_b = user_b_ratings / norm_b

print("歸一化后的評分向量:")
print("用戶A:", normalized_a)
print("用戶B:", normalized_b)
print()

# 計算歸一化后的點積相似度
dot_product_normalized = np.dot(normalized_a, normalized_b)
print(f"歸一化后點積相似度: {dot_product_normalized:.4f}")

# 分析差異
print("\n分析:")
print("歸一化前,用戶A的5星是絕對值5,用戶B的5星也是絕對值5")
print("歸一化后,用戶A的5星被縮放為{:.4f},用戶B的5星被縮放為{:.4f}".format(
    normalized_a[0], normalized_b[0]))
print("這意味著用戶A的5星在其評分體系中占比更大,但失去了'絕對值5星'的語義")

? 結論:在推薦系統、經濟數據對比、信號強度分析等場景中,向量的模長(絕對評分、經濟總量、信號振幅)是核心比較信息的一部分。此時,不應使用歸一化。

四、實戰決策指南:如何選擇?

下次當你猶豫是否要歸一化時,問自己這三個問題:

  1. 模長差異是噪聲還是信息?

  2. 我想找"同類"還是"克隆"?

  3. 我的算法核心是什么?

最后的建議:
在沒有明確先驗知識時,先嘗試歸一化通常是更安全的選擇,因為它能消除很多量級帶來的偏差。但最好的方法永遠是基于你的業務目標,構建一個驗證集,同時試驗兩種方案,讓最終的模型效果告訴你答案。

上一篇:

Poe API全面開放:30天Apigee副業API開發月入過萬
最后一篇
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費