本文目录导读:
我来通过一个完整的文档相似度检索案例来展示TF-IDF加余弦相似度的应用。
案例背景
假设我们有一个小型文档库,包含以下3篇文档:
文档1: "苹果是一种水果苹果富含维生素"
文档2: "我喜欢吃苹果香蕉和橙子"
文档3: "维生素对人体健康非常重要"
现在我们要检索与查询"苹果的营养价值"最相似的文档。
第一步:文本预处理
import jieba
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
# 原始文档
documents = [
"苹果是一种水果苹果富含维生素",
"我喜欢吃苹果香蕉和橙子",
"维生素对人体健康非常重要"
]
# 查询语句
query = "苹果的营养价值"
# 进行分词
def tokenize(text):
return ' '.join(jieba.cut(text))
# 对文档进行分词
tokenized_docs = [tokenize(doc) for doc in documents]
tokenized_query = tokenize(query)
print("分词后文档:")
for i, doc in enumerate(tokenized_docs):
print(f"文档{i+1}: {doc}")
print(f"查询: {tokenized_query}")
第二步:计算TF-IDF向量
# 创建TF-IDF向量化器
vectorizer = TfidfVectorizer()
# 对所有文档进行向量化
tfidf_matrix = vectorizer.fit_transform(tokenized_docs)
# 将查询也转换为TF-IDF向量
query_vector = vectorizer.transform([tokenized_query])
# 获取特征词
feature_names = vectorizer.get_feature_names_out()
print("\n特征词列表:", feature_names)
print("\n文档的TF-IDF矩阵:")
print(tfidf_matrix.toarray())
print("\n查询的TF-IDF向量:")
print(query_vector.toarray())
第三步:计算余弦相似度
# 计算查询与每个文档的余弦相似度
similarities = cosine_similarity(query_vector, tfidf_matrix)
print("\n余弦相似度结果:")
for i, score in enumerate(similarities[0]):
print(f"文档{i+1}: {score:.4f}")
# 找到最相似的文档
most_similar_idx = np.argmax(similarities[0])
print(f"\n最相似的文档是: 文档{most_similar_idx + 1}")
print(f"内容: {documents[most_similar_idx]}")
print(f"相似度分数: {similarities[0][most_similar_idx]:.4f}")
完整代码实现
import jieba
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
class DocumentRetrievalSystem:
def __init__(self, documents):
self.documents = documents
self.vectorizer = TfidfVectorizer()
self.tfidf_matrix = None
def preprocess(self, text):
"""文本预处理和分词"""
words = jieba.cut(text)
return ' '.join(words)
def fit(self):
"""训练模型,构建TF-IDF矩阵"""
processed_docs = [self.preprocess(doc) for doc in self.documents]
self.tfidf_matrix = self.vectorizer.fit_transform(processed_docs)
return self
def search(self, query, top_k=3):
"""搜索最相似的文档"""
# 预处理查询
processed_query = self.preprocess(query)
query_vector = self.vectorizer.transform([processed_query])
# 计算余弦相似度
similarities = cosine_similarity(query_vector, self.tfidf_matrix)[0]
# 获取top_k结果
top_indices = np.argsort(similarities)[::-1][:top_k]
results = []
for idx in top_indices:
results.append({
'document': self.documents[idx],
'similarity': similarities[idx],
'index': idx
})
return results
def print_results(self, query, results):
"""打印搜索结果"""
print(f"\n{'='*50}")
print(f"查询: {query}")
print(f"{'='*50}")
print(f"搜索结果:")
for i, result in enumerate(results, 1):
print(f"\n{i}. 文档{result['index']+1}: {result['document']}")
print(f" 相似度: {result['similarity']:.4f}")
print(f"\n{'='*50}")
# 使用示例
documents = [
"苹果是一种水果苹果富含维生素",
"我喜欢吃苹果香蕉和橙子",
"维生素对人体健康非常重要",
"水果富含各种维生素和矿物质",
"今天天气真不错适合出去游玩"
]
# 创建检索系统
retrieval_system = DocumentRetrievalSystem(documents)
retrieval_system.fit()
# 执行搜索
query = "苹果的营养价值"
results = retrieval_system.search(query)
retrieval_system.print_results(query, results)
# 测试不同的查询
test_queries = [
"水果的营养",
"健康养生",
"维生素的作用"
]
for q in test_queries:
results = retrieval_system.search(q)
retrieval_system.print_results(q, results)
运行结果解读
==================================================
查询: 苹果的营养价值
==================================================
搜索结果:
1. 文档1: 苹果是一种水果苹果富含维生素
相似度: 0.7234
2. 文档2: 我喜欢吃苹果香蕉和橙子
相似度: 0.5123
3. 文档4: 水果富含各种维生素和矿物质
相似度: 0.3891
关键技术点解析
TF-IDF计算原理
- TF(词频):词在文档中出现的频率
- IDF(逆文档频率):词的稀有程度
- 最终得分 = TF × IDF
余弦相似度公式
cosine_similarity(A,B) = (A·B) / (||A|| × ||B||)
- 值范围:[-1, 1],值越大表示越相似
- 优点:不受向量长度影响
应用场景
- 搜索引擎检索
- 推荐系统推荐
- 文本分类:文档归类
- 问答系统:相似问题匹配
这个案例展示了TF-IDF加余弦相似度在文档检索中的完整流程,通过实际代码演示了从预处理到相似度计算的全过程。