词汇/表达差异-3-海明距离(Hamming distance)
海明距离(Hamming Distance)是一种简单而高效的度量方法,用于衡量两个等长字符串(或二进制序列)在相同位置上不同字符的数量。
·
1.基本原理
海明距离(Hamming Distance)是一种简单而高效的度量方法,用于衡量两个等长字符串(或二进制序列)在相同位置上不同字符的数量。
- 取值范围:非负整数(0到字符串/向量长度),值越大表示差异越显著;
- 特殊说明:仅适用于等长的输入,若两个输入长度不同,通常需要先补零/截断至相同长度,否则无法计算(这是海明距离的核心约束)。
2.算法步骤
步骤1:确保两个输入长度相同
这是前提条件
步骤2:逐位对比,统计“不同位置”的数量
对两个输入的每一个对应位置进行比较,记录不同的位置数,这个数字就是海明距离。
3. 扩展:海明相似度
实际使用中也常计算海明相似度,通常定义为:相似度 = 1 - (海明距离 / 字符串长度),取值范围为[0,1],值越大表示越相似。比如上述示例1的海明相似度=1 - 2/5 = 0.6。
3.优缺点适用场景
| 特点 | 说明 |
|---|---|
| ✅ 核心优点 | 计算极快:( O(n) ) 时间,无复杂操作 。 内存高效:只需逐位比较,无需存储中间状态。 理论清晰:在编码理论中有严格数学基础。 适用于高维二值数据:如 simHash、LSH、特征哈希。 |
| ❌ 主要缺点 | 要求等长:无法直接比较 “abc” 和 “abcd”。 忽略语义与顺序:“abc” vs “cba” 距离=2,但可能语义相同。 不适用于非符号数据:不能直接用于实数向量(需先二值化)。 对局部敏感哈希外的文本效果有限:对自然语言拼写错误不如编辑距离鲁棒 |
| 🛠️ 典型使用场景 | simHash / LSH 近似去重:将文档哈希为 64/128 位指纹,用海明距离判断是否相似(如网页去重) 错误检测码(ECC):检测/纠正通信中的比特错误(如 Hamming Code) 生物信息学:比较 DNA 序列(当已对齐且等长时) 密码学:分析加密算法的雪崩效应(输入微变 → 输出海明距离大) 机器学习特征比较:比较 one-hot 编码、二值化特征向量 实体对齐中的签名匹配:对实体生成属性签名(如“性别+城市+职业” → 二进制串),快速初筛 |
💡 关键洞察:海明距离不是为自然语言设计的,而是为结构化符号序列或哈希码服务的。在 NLP 中,它主要作为底层工具(如 simHash 的组成部分),而非直接用于句子相似度。
4.与其他距离的对比
| 方法 | 是否需等长 | 适合文本? | 适合二值数据? |
|---|---|---|---|
| 海明距离 | ✅ 是 | ❌ 否(除非哈希后) | ✅ 是 |
| 编辑距离 | ❌ 否 | ✅ 是 | ⚠️ 可但低效 |
| 余弦相似度 | ❌ 否(向量可不同源) | ✅ 是(配合 TF-IDF/BERT) | ✅ 是(二值向量) |
| Jaccard | ❌ 否 | ✅ 是(词集) | ✅ 是 |
5.主流库推荐
| 方案 | 性能 | 易用性 | 支持类型 | 推荐度 |
|---|---|---|---|---|
✅ scipy.spatial.distance.hamming |
⚡ 快(C 优化) | 高 | 字符串、数组、布尔向量 | ★★★★★ |
RapidFuzz |
⚡ 快 | 高 | 字符串 | ★★★★☆ |
python-Levenshtein |
⚡ 快 | 中 | 字符串 | ★★★☆ |
| 手写循环 / NumPy | 慢 / 中 | 低 / 中 | 灵活但易错 | ★★ |
工程 / 大规模计算:scipy / numpy
字符串 / 教学 / NLP:textdistance / jellyfish
6.使用
import numpy as np
# 定义两个二进制向量(等长)
vec1 = np.array([1, 0, 1, 1, 0], dtype=int)
vec2 = np.array([1, 0, 0, 1, 1], dtype=int)
# 计算海明距离:统计不同元素的数量
hamming_dist = np.sum(vec1 != vec2)
print(f"向量海明距离:{hamming_dist}") # 输出:2
# 计算多个向量与目标向量的海明距离
vecs = np.array([[1,0,0,1,1], [1,0,1,0,0], [1,1,1,1,1]], dtype=int)
distances = np.sum(vecs != vec1, axis=1)
print(f"批量向量海明距离:{distances}") # 输出:[2 2 1]
from scipy.spatial.distance import hamming
import numpy as np
# 字符串(需转为 list 或 array)
a = "karolin"
b = "kathrin"
dist = hamming(list(a), list(b)) * len(a) # scipy 返回比例,乘以长度得整数距离
print(dist) # → 3.0
# 二进制数组(更常见)
x = np.array([1, 0, 1, 1, 0])
y = np.array([1, 1, 1, 0, 0])
print(hamming(x, y) * len(x)) # → 2.0
# 布尔向量
print(hamming([True, False, True], [True, True, False]) * 3) # → 2.0
import rapidfuzz
from rapidfuzz import distance
# 计算字符串的海明距离(需等长)
hamming_dist = distance.Hamming.distance("10110", "10011")
hamming_sim = distance.Hamming.similarity("10110", "10011") # 相似性(长度 - 距离)
print(f"海明距离:{hamming_dist},海明相似性:{hamming_sim}")
# 输出:海明距离:2,海明相似性:3
# 批量处理(从候选列表中找最相似的字符串)
candidates = ["10011", "10100", "11111"]
matches = rapidfuzz.process.extract("10110", candidates, scorer=distance.Hamming.distance, limit=2)
print(f"批量匹配结果:{matches}")
# 输出:[('10011', 2, 0), ('10100', 2, 1)](元组为:候选字符串、海明距离、索引)
更多推荐
所有评论(0)