本文目录导读:
语义相似度就是衡量两个文本(词、句子、段落)在“意思”上有多接近,而不是看它们字面上有多少共同字符。
计算语义相似度的方法主要可以分为三代:基于统计的、基于向量空间的、以及基于深度学习的(最主流)。
以下是目前最主流和常见的计算方法:
核心思路:从“字符匹配”到“语义匹配”
- 传统方法(如编辑距离): 认为“猫吃鱼”和“鱼吃猫”不相似。(字面不同)
- 语义方法(如词向量): 认为“猫吃鱼”和“猫咪爱吃鱼”很相似。(意思相同)
- 高级语义方法(如BERT): 认为“猫吃鱼”和“猫咪很享受鱼肉”也相似。(即使字词不同,但意思关联)
基于向量空间模型(最经典、最常用)
这是目前深度学习时代的基础,核心思想是:将文本变成一个高维空间中的“向量”,然后用计算两个向量之间的“距离”或“夹角”来衡量相似度。
词袋模型(Bag of Words, BoW) + TF-IDF
- 做法: 统计句子中每个词出现的次数或重要性(TF-IDF),形成一个稀疏向量。
- 缺点: 忽略词序和上下文(“我打你”和“你打我”向量相同),且无法处理同义词(“汽车”和“轿车”被视为完全不同的词)。
- 相似度计算: 余弦相似度。
静态词向量(Word2Vec / GloVe) —— 里程碑式进步
- 做法: 预训练好的词向量,每个词被映射到一个稠密向量(如300维)。
- 如何算句子: 将句子中所有词的向量取平均。
- 优点: “国王 - 男人 + 女人 = 女王”,能捕捉到词与词之间的关系。
- 缺点: 无法解决多义词问题(“苹果”手机 vs “苹果”水果,向量是一样的)。
- 相似度计算: 余弦相似度。
深度上下文向量(BERT / Sentence-BERT) —— 目前最先进方法
- 做法: 使用预训练语言模型(如BERT),输入“今天天气真不错”和“今天晴空万里”,模型会考虑每个词的上下文。
- 优点: 完美解决多义词、同义词、语序问题,上述两句话会被认为非常相似。
- 如何计算:
- 方法A(传统): 提取BERT的[CLS]标记向量作为句子表示,算余弦相似度,但直接算效果并不好。
- 方法B(推荐): 使用Sentence-BERT(SBERT),这是一个专门为计算相似度而微调的模型,它将两个句子分别编码成向量,然后输入一个分类器或直接算余弦相似度。这是目前实际应用中的SOTA(State Of The Art,最先进水平)。
经典的非向量方法(适合快速理解或基线对比)
这些方法通常更直观,但精度不如深度模型。
基于字符串的
- 编辑距离(Levenshtein Distance): 把一个字符串变成另一个需要的最少编辑次数(增、删、改),距离越小,越相似,对拼写错误有效,但对语义完全无效。
- 杰卡德相似度(Jaccard Similarity): 两个集合(如单词集合)交集大小除以并集大小,对“猫吃鱼”和“鱼吃猫”结果很高,但语义相反。
基于知识的(WordNet / 知网)
- 做法: 利用大规模语义词典(如WordNet),狗”和“猫”在百科层级中同属“哺乳动物”,路径较短,相似度较高。
- 缺点: 需要维护庞大的知识库,且对网络新词(“YYDS”、“躺平”)几乎无效。
如何选择?(实用建议)
| 你的场景 | 推荐方法 | 速度 | 准确度 |
|---|---|---|---|
| 快速试算、简单理解 | TF-IDF + 余弦相似度 | 极快 | 低 |
| 拼写校正或模糊匹配 | 编辑距离 | 快 | 极低(语义无关) |
| 同义词识别(如:高兴 vs 快乐) | Word2Vec / GloVe | 快 | 中 |
| 句子匹配、客服问答、论文查重 | Sentence-BERT | 中等 | 高 |
| 情感分析、复杂推理 | BERT + 微调分类(如输入两个句子,输出0-1分数) | 中等 | 极高 |
具体计算步骤(以最主流的 Sentence-BERT 为例)
-
安装库:
pip install sentence-transformers -
加载模型:
from sentence_transformers import SentenceTransformer # 模型:'all-MiniLM-L6-v2' (快, 轻量) 或 'all-mpnet-base-v2' (慢, 更准) model = SentenceTransformer('all-MiniLM-L6-v2') -
编码成向量:
sentence1 = "我今天心情非常好" sentence2 = "今天我的情绪非常愉快" embedding1 = model.encode(sentence1) embedding2 = model.encode(sentence2) # embedding 是一个 384 维的数组
-
计算余弦相似度:
from sklearn.metrics.pairwise import cosine_similarity import numpy as np similarity = cosine_similarity([embedding1], [embedding2]) print(similarity[0][0]) # 输出 0.92 (非常相似)
- 简单场景(仅看字符):用 TF-IDF。
- 语义理解(手机 vs 电话):用 Word2Vec。
- 最佳实践(句子/段落级别):用 Sentence-BERT,它结合了深度上下文理解与高效的向量匹配,是目前工业界和学术界最常用的方案。
如果你有具体的语言(如中文)或算力限制(比如必须在手机端跑),选择会有所不同,需要我进一步介绍中文领域的特殊处理(如分词、中文预训练模型)吗?
标签: 余弦相似度