如何基于TF-IDF与成对相似度实现文档搜索?(pandas/sklearn实践)
基于TF-IDF与成对相似度实现文档搜索的后续步骤
你已经搞定了语料库构建、预处理和TF-IDF模型训练这些基础工作,接下来几步就能把搜索功能搭起来,我一步步给你拆解:
1. 生成待搜索文本的TF-IDF向量
⚠️ 这里有个关键注意点:必须用你之前训练好的TfidfVectorizer实例来转换待搜索文本,绝对不能重新调用fit方法!否则会生成新的词汇表,和语料库的TF-IDF矩阵维度不匹配,相似度计算就完全失效了。
示例代码:
# 假设你之前训练的TF-IDF向量器叫tfidf_vectorizer # 待搜索文本的预处理后的DataFrame叫search_df,预处理列命名为'processed_text' search_tfidf = tfidf_vectorizer.transform(search_df['processed_text'])
2. 计算成对相似度(优先用余弦相似度)
文本场景下最常用的相似度算法就是余弦相似度,它能衡量两个TF-IDF向量在空间中的夹角,值越接近1代表文档越相似。sklearn的cosine_similarity可以直接帮你计算待搜索文本和整个语料库的相似度矩阵。
示例代码:
from sklearn.metrics.pairwise import cosine_similarity # 假设语料库的TF-IDF矩阵叫corpus_tfidf similarity_scores = cosine_similarity(search_tfidf, corpus_tfidf)[0] # 这里取[0]是因为如果search_df只有一条待搜索文本,结果是(1, N)的矩阵,第一行就是每个语料库文档的相似度分数
3. 关联分数与原语料库,排序取Top N结果
把相似度分数和你的语料库DataFrame绑定,然后按分数降序排列,就能得到最相关的文档列表。
示例代码:
# 假设你的语料库DataFrame叫corpus_df,包含原始文本、文档ID等信息 corpus_df['similarity_score'] = similarity_scores # 按相似度降序排序,取前5个最相关的文档 top_results = corpus_df.sort_values(by='similarity_score', ascending=False).head(5) # 打印核心结果看看 print(top_results[['document_id', 'original_text', 'similarity_score']])
4. 封装成可复用的搜索函数
把上面的步骤打包成函数,以后输入搜索词就能直接得到结果,用起来更方便:
def search_documents(query_text, tfidf_vectorizer, corpus_tfidf, corpus_df, top_n=5): # 预处理查询文本(必须和你预处理语料库的逻辑完全一致!) processed_query = preprocess_text(query_text) # 假设你有一个preprocess_text预处理函数 # 转换为TF-IDF向量 query_tfidf = tfidf_vectorizer.transform([processed_query]) # 计算相似度 similarity_scores = cosine_similarity(query_tfidf, corpus_tfidf)[0] # 关联分数并排序 corpus_df['similarity_score'] = similarity_scores top_results = corpus_df.sort_values(by='similarity_score', ascending=False).head(top_n) return top_results # 使用示例 query = "你的搜索关键词或完整句子" results = search_documents(query, tfidf_vectorizer, corpus_tfidf, corpus_df) print(results)
一些实用优化技巧
- 预处理一致性:待搜索文本的预处理逻辑(分词、去停用词、小写化、词干/词形还原等)必须和语料库的预处理完全相同,否则会严重影响相似度计算的准确性。
- 阈值过滤:如果结果太多,可以设置最低相似度分数(比如0.3),过滤掉不相关的文档:
filtered_results = top_results[top_results['similarity_score'] > 0.3] - 调整TF-IDF参数:比如设置
ngram_range=(1,2)加入二元词组、用max_df/min_df过滤太常见或太罕见的词,能进一步提升搜索效果。 - 尝试其他相似度算法:除了余弦相似度,也可以试试欧氏距离(值越小越相似),不过余弦相似度在文本场景下表现最优。
内容的提问来源于stack exchange,提问作者FChris




