你清楚如何用Python计算两段文本的余弦相似度吗

访客 自然语言处理 1

本文目录导读:

  1. 方法1:使用sklearn(推荐)
  2. 方法2:手动实现
  3. 方法3:使用预训练词向量
  4. 方法4:使用sentence-transformers(语义相似度)
  5. 实用比较与建议
  6. 完整示例:文本相似度比较工具

是的,我清楚如何用Python计算两段文本的余弦相似度,下面是几种常见的方法:

方法1:使用sklearn(推荐)

from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# 两段文本
text1 = "我喜欢编程和人工智能"
text2 = "我对编程和机器学习很感兴趣"
# 方法1a:使用词频向量
vectorizer = CountVectorizer()
vectors = vectorizer.fit_transform([text1, text2])
similarity = cosine_similarity(vectors[0:1], vectors[1:2])
print(f"词频向量余弦相似度: {similarity[0][0]:.4f}")
# 方法1b:使用TF-IDF(通常效果更好)
tfidf_vectorizer = TfidfVectorizer()
tfidf_vectors = tfidf_vectorizer.fit_transform([text1, text2])
tfidf_similarity = cosine_similarity(tfidf_vectors[0:1], tfidf_vectors[1:2])
print(f"TF-IDF余弦相似度: {tfidf_similarity[0][0]:.4f}")

方法2:手动实现

import re
from collections import Counter
import math
def tokenize(text):
    """分词并转换为小写"""
    return re.findall(r'\w+', text.lower())
def get_vector(tokens, vocab):
    """将词转换为向量"""
    token_count = Counter(tokens)
    return [token_count[word] for word in vocab]
def cosine_similarity_manual(vec1, vec2):
    """计算余弦相似度"""
    dot_product = sum(a * b for a, b in zip(vec1, vec2))
    norm1 = math.sqrt(sum(a ** 2 for a in vec1))
    norm2 = math.sqrt(sum(b ** 2 for b in vec2))
    if norm1 == 0 or norm2 == 0:
        return 0.0
    return dot_product / (norm1 * norm2)
# 使用示例
text1 = "我喜欢编程和人工智能"
text2 = "我对编程和机器学习很感兴趣"
tokens1 = tokenize(text1)
tokens2 = tokenize(text2)
# 构建词汇表
vocab = list(set(tokens1 + tokens2))
# 转换为向量
vec1 = get_vector(tokens1, vocab)
vec2 = get_vector(tokens2, vocab)
similarity = cosine_similarity_manual(vec1, vec2)
print(f"手动实现余弦相似度: {similarity:.4f}")

方法3:使用预训练词向量

# 安装: pip install gensim
from gensim.models import KeyedVectors
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
def text_to_vector(text, model):
    """将文本转换为词向量平均"""
    words = text.lower().split()
    vectors = []
    for word in words:
        if word in model:
            vectors.append(model[word])
    if len(vectors) == 0:
        return np.zeros(model.vector_size)
    return np.mean(vectors, axis=0)
# 使用示例(需要下载预训练词向量)
# 下载地址: https://github.com/RaRe-Technologies/gensim-data
# model = KeyedVectors.load_word2vec_format('path/to/word2vec.bin', binary=True)
# 模拟示例(假设有模型)
# text1_vector = text_to_vector("I love programming", model)
# text2_vector = text_to_vector("I enjoy coding", model)
# similarity = cosine_similarity([text1_vector], [text2_vector])[0][0]

方法4:使用sentence-transformers(语义相似度)

# 安装: pip install sentence-transformers
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
# 加载预训练模型(第一次使用会自动下载)
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
# 文本(支持中文)
text1 = "我喜欢编程和人工智能"
text2 = "我对编程和机器学习很感兴趣"
# 生成句子嵌入
embedding1 = model.encode([text1])
embedding2 = model.encode([text2])
# 计算相似度
similarity = cosine_similarity(embedding1, embedding2)
print(f"语义余弦相似度: {similarity[0][0]:.4f}")

实用比较与建议

方法 优点 缺点 适用场景
词频向量 简单快速 忽略语义 短文本,关键词匹配
TF-IDF 考虑词的重要性 忽略语义 文档检索,关键词提取
手动实现 理解原理 效率低 学习目的
词向量 包含语义 需要预训练模型 语义相似度计算
sentence-transformers 最先进的语义理解 需要下载模型 复杂语义匹配

完整示例:文本相似度比较工具

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import jieba
def compute_text_similarity(text1, text2, method='tfidf'):
    """计算文本相似度"""
    # 中文分词
    def chinese_tokenize(text):
        return ' '.join(jieba.cut(text))
    # 预处理
    proc_text1 = chinese_tokenize(text1)
    proc_text2 = chinese_tokenize(text2)
    if method == 'tfidf':
        vectorizer = TfidfVectorizer()
        vectors = vectorizer.fit_transform([proc_text1, proc_text2])
        similarity = cosine_similarity(vectors[0:1], vectors[1:2])
        return similarity[0][0]
    else:
        vectorizer = CountVectorizer()
        vectors = vectorizer.fit_transform([proc_text1, proc_text2])
        similarity = cosine_similarity(vectors[0:1], vectors[1:2])
        return similarity[0][0]
# 测试
text1 = "我喜欢编程和人工智能"
text2 = "我对编程和机器学习很感兴趣"
print(f"TF-IDF相似度: {compute_text_similarity(text1, text2, 'tfidf'):.4f}")
print(f"词频相似度: {compute_text_similarity(text1, text2, 'count'):.4f}")

选择哪种方法取决于你的具体需求:

  • 快速原型:使用sklearn的TF-IDF
  • 重视语义:使用sentence-transformers
  • 学习原理:手动实现
  • 中文处理:考虑分词后再计算

标签: 余弦相似度

抱歉,评论功能暂时关闭!