从搜索引擎到推荐系统:手把手用TF-IDF和Python实现简易文本相似度匹配与文档检索
从搜索引擎到推荐系统手把手用TF-IDF和Python实现简易文本相似度匹配与文档检索在信息爆炸的时代如何从海量文本中快速找到相关内容无论是构建企业内部文档检索系统还是为新闻网站添加相关阅读功能文本相似度匹配都是核心技术。本文将带你用Python和TF-IDF算法从零实现一个可落地的文本检索系统。1. 理解TF-IDF的核心价值TF-IDFTerm Frequency-Inverse Document Frequency是自然语言处理中的经典算法它通过量化词语在文档中的重要性将文本转换为数学向量。这种转换使得计算机能够理解文本内容进而实现相似度计算。为什么选择TF-IDF而不是简单关键词匹配传统关键词匹配无法处理同义词问题如Python和蟒蛇语言忽略常见词的影响如的、是等停用词无法衡量词语的区分度专业术语比通用词更有价值# TF-IDF基本公式示例 def tf(term, document): return document.count(term) / len(document.split()) def idf(term, corpus): import math doc_count sum(1 for doc in corpus if term in doc) return math.log(len(corpus)/(1 doc_count)) def tfidf(term, document, corpus): return tf(term, document) * idf(term, corpus)2. 构建文本检索系统的四步流程2.1 数据准备与预处理任何NLP项目的第一步都是数据清洗。我们以新闻数据集为例import re from nltk.corpus import stopwords def preprocess(text): # 去除非字母字符 text re.sub(r[^a-zA-Z\s], , text) # 转换为小写 text text.lower() # 移除停用词 stop_words set(stopwords.words(english)) words [w for w in text.split() if w not in stop_words] return .join(words) # 示例文档集 documents [ The quick brown fox jumps over the lazy dog, Never jump over the lazy dog quickly, Bright vixens jump; dozy fowl quack ] cleaned_docs [preprocess(doc) for doc in documents]2.2 向量化与特征提取使用scikit-learn的TfidfVectorizer将文本转换为特征向量from sklearn.feature_extraction.text import TfidfVectorizer vectorizer TfidfVectorizer( ngram_range(1, 2), # 考虑1-2个词的组合 max_features1000, # 限制特征数量 min_df2 # 忽略低频词 ) tfidf_matrix vectorizer.fit_transform(cleaned_docs) # 查看特征词 print(vectorizer.get_feature_names_out()[:10])2.3 相似度计算实战余弦相似度是衡量向量间夹度的标准方法from sklearn.metrics.pairwise import cosine_similarity def search(query, docs, vectorizer, top_n3): # 预处理查询 processed_query preprocess(query) # 转换为TF-IDF向量 query_vec vectorizer.transform([processed_query]) # 计算相似度 sim_scores cosine_similarity(query_vec, tfidf_matrix) # 获取最相似文档 top_indices sim_scores.argsort()[0][-top_n:][::-1] return [(i, docs[i], sim_scores[0,i]) for i in top_indices] # 示例查询 results search(fast fox, documents, vectorizer) for idx, doc, score in results: print(f文档{idx} (相似度:{score:.2f}): {doc})2.4 系统优化与调参提升检索质量的实用技巧停用词优化# 自定义停用词表 custom_stopwords stopwords.words(english) [said, would] vectorizer.set_params(stop_wordscustom_stopwords)权重调整# 使用sublinear_tf平滑词频 TfidfVectorizer(sublinear_tfTrue)相似度阈值设定# 过滤低质量匹配 MIN_SIMILARITY 0.3 filtered_results [r for r in results if r[2] MIN_SIMILARITY]3. 从检索到推荐TF-IDF的高级应用3.1 文档去重技术利用相似度检测重复或近似内容def find_duplicates(docs, threshold0.9): sim_matrix cosine_similarity(tfidf_matrix) duplicates set() for i in range(len(docs)): for j in range(i1, len(docs)): if sim_matrix[i,j] threshold: duplicates.add((i,j)) return duplicates3.2 混合推荐系统结合TF-IDF与用户行为数据def hybrid_recommend(user_history, all_docs): # 计算内容相似度 history_vec vectorizer.transform(user_history) avg_vec history_vec.mean(axis0) content_scores cosine_similarity(avg_vec, tfidf_matrix) # 获取用户行为权重假设已有 behavior_weights get_user_behavior_weights(user_history) # 混合推荐得分 hybrid_scores 0.7*content_scores 0.3*behavior_weights return hybrid_scores.argsort()[0][-5:][::-1]3.3 实时检索优化对于大规模文档集使用近似最近邻(ANN)加速from sklearn.neighbors import NearestNeighbors # 构建ANN索引 nbrs NearestNeighbors(n_neighbors5, algorithmball_tree).fit(tfidf_matrix) # 快速查询 distances, indices nbrs.kneighbors(query_vec)4. 超越TF-IDFTF-IWF与进阶技巧当处理特定领域文本时传统TF-IDF可能表现不佳。TF-IWFTerm Frequency-Inverse Word Frequency是改进方案class TfIwfVectorizer(TfidfVectorizer): def _compute_idf(self, X): 重写IDF计算为IWF n_samples, n_features X.shape df np.squeeze(np.asarray(X.sum(axis0))) total_words df.sum() return np.log(1 total_words / (1 df))关键改进点对比特性TF-IDFTF-IWF权重计算文档频率倒数词频倒数领域适应性一般更强同类文档处理可能掩盖关键词更好区分实现复杂度简单中等在实际项目中我发现结合两种方法能取得更好效果。可以先使用TF-IDF进行初筛再用TF-IWF对结果集进行重排序。这种分层处理方式既保证了效率又提升了精度。