回顧:TF-IDF算法詳解與實踐總結
上一篇文章我們深入剖析了TF-IDF的原理與細節,但實踐才是檢驗真理的唯一標準!今天,我們將從“紙上談兵”轉向“實戰演練”:通過純Python手寫實現與調用sklearn
工具包兩種方式,帶你一步步完成TF-IDF在真實場景中的應用
- 關鍵詞提取:如何從一篇長文中精準抓取核心詞匯?
- 文本分類:如何讓機器自動識別“AI”、“ML”、“DL”類別的文本?
- 信息檢索:如何根據查詢語句,從文檔庫中找到最相關的內容?
TF-IDF 基類實現
手搓版本
import mathclass TFIDFBase:def __init__(self, corpus):self.corpus = corpusself.tokenized_corpus = [preprocess(doc) for doc in corpus]self.N = len(corpus) # 文檔總數self.df = self._compute_df()self.idf = self._compute_idf()def _compute_df(self):"""計算文檔頻率 (Document Frequency)"""df = defaultdict(int)for tokens in self.tokenized_corpus:unique_tokens = set(tokens)for token in unique_tokens:df[token] += 1return dfdef _compute_idf(self):"""計算逆文檔頻率 (IDF)"""idf = defaultdict(float)for token, count in self.df.items():idf[token] = math.log(self.N / (count + 1)) + 1 # 平滑處理return idfdef compute_tf(self, tokens):"""計算詞頻 (TF)"""tf = defaultdict(int)total = len(tokens)for token in tokens:tf[token] += 1 / total # 歸一化return tfdef compute_tfidf(self, tf):"""計算 TF-IDF 向量"""return {token: tf[token] * self.idf[token] for token in tf}def get_tfidf_vector(self):"""生成整個語料庫的 TF-IDF 向量"""tfidf_vectors = []for tokens in self.tokenized_corpus:tf = self.compute_tf(tokens)tfidf = self.compute_tfidf(tf)tfidf_vectors.append(tfidf)return tfidf_vectors
依賴版本
from sklearn.feature_extraction.text import TfidfVectorizervectorizer = TfidfVectorizer(tokenizer=preprocess, # 指定自定義分詞函數token_pattern=r"(?u)\b\w+\b", # 匹配中文分詞結果max_features=1000 # 控制詞匯表大小
)
文本預處理
import jieba
import nltk
from nltk.corpus import stopwordstry:nltk.download('stopwords')stopwords_cn = stopwords.words('chinese')print("已下載 NLTK 中文停用詞")
except:# 若 nltk 中文停用詞缺失,手動補充常用中文停用詞stopwords_cn = ['的', '了', '和', '是', '在', '中', '也', '都', '而', '就','那', '這', '之', '為', '對', '與', '于', '上', '下', '前']# 中文文本預處理(分詞 + 去停用詞)
def preprocess(text):tokens = jieba.cut(text)return [token for token in tokens if token not in stopwords_cn and token.strip()]
TD-IDF 關鍵詞提取
手搓版本
提取關鍵詞
class KeywordExtractor(TFIDFBase):def extract_keywords(self, top_k=5):"""提取每個文檔的 top-k 關鍵詞"""tfidf_vectors = self.get_tfidf_vector()results = []for idx, tfidf in enumerate(tfidf_vectors):sorted_keywords = sorted(tfidf.items(), key=lambda x: -x[1])[:top_k]results.append([kw[0] for kw in sorted_keywords])return results
執行
corpus = ["自然語言處理是人工智能領域的一個重要分支","信息檢索技術幫助我們從大量文檔中找到相關內容","BM25算法是信息檢索中常用的經典算法","中文分詞是中文自然語言處理的基礎步驟","搜索引擎使用各種算法來提高搜索結果的相關性","TF-IDF和BM25都是基于統計的檢索模型","深度學習在自然語言處理中取得了顯著進展","倒排索引是信息檢索系統的核心技術之一","查詢擴展可以提高信息檢索的召回率","準確率和召回率是評價信息檢索系統的重要指標"
]extractor = KeywordExtractor(corpus)
keywords = extractor.extract_keywords(top_k=3)
for i, kws in enumerate(keywords):print(f"Document {i + 1} Keywords: {kws}")
結果
Document 1 Keywords: ['人工智能', '領域', '一個']
Document 2 Keywords: ['技術', '文檔', '找到']
Document 3 Keywords: ['算法', '常用', '經典']
Document 4 Keywords: ['中文', '分詞', '基礎']
Document 5 Keywords: ['搜索引擎', '搜索', '相關性']
Document 6 Keywords: ['TF', '-', 'IDF']
Document 7 Keywords: ['深度', '學習', '進展']
Document 8 Keywords: ['倒排', '索引', '核心技術']
Document 9 Keywords: ['查詢', '擴展', '提高']
Document 10 Keywords: ['準確率', '評價', '指標']
依賴版本
執行
# 擬合語料庫并生成TF-IDF矩陣
tfidf_matrix = vectorizer.fit_transform(corpus)# 提取關鍵詞(每個文檔的Top N關鍵詞)
for i, text in enumerate(corpus):feature_index = tfidf_matrix[i, :].nonzero()[1] # 非零元素的索引tfidf_scores = zip(feature_index, [tfidf_matrix[i, x] for x in feature_index]) # (詞索引, 權重)sorted_tfidf = sorted(tfidf_scores, key=lambda x: x[1], reverse=True) # 按權重排序top_n = 3 # 提取每個文檔的前3個關鍵詞keywords = [vectorizer.get_feature_names_out()[idx] for idx, score in sorted_tfidf[:top_n]]print(f"文檔 {i + 1} 的關鍵詞: {keywords}")
結果
文檔 1 的關鍵詞: ['人工智能', '領域', '一個']
文檔 2 的關鍵詞: ['技術', '文檔', '找到']
文檔 3 的關鍵詞: ['算法', '常用', '經典']
文檔 4 的關鍵詞: ['中文', '分詞', '基礎']
文檔 5 的關鍵詞: ['搜索引擎', '搜索', '相關性']
文檔 6 的關鍵詞: ['tf', '-', 'idf']
文檔 7 的關鍵詞: ['深度', '學習', '進展']
文檔 8 的關鍵詞: ['倒排', '索引', '核心技術']
文檔 9 的關鍵詞: ['查詢', '擴展', '提高']
文檔 10 的關鍵詞: ['準確率', '評價', '指標']
TF-IDF 文本分類
設置的分類語料以及標簽
corpus = [# AI類"人工智能正在改變醫療、金融和教育等多個行業","自然語言處理技術使計算機能夠理解和生成人類語言","計算機視覺是人工智能領域的重要研究方向之一","智能語音助手通過人工智能實現了語音識別和對話功能","人工智能倫理問題成為學術界和工業界討論的焦點","自動駕駛技術依賴人工智能實現環境感知和決策","人工智能在游戲開發中用于創建智能NPC和動態劇情","工業機器人通過人工智能優化生產流程和質量檢測","人工智能與物聯網結合推動了智能家居的發展","人工智能輔助診斷系統能快速分析醫學影像并提供建議",# ML類"機器學習算法通過數據訓練模型來預測未來趨勢","監督學習需要標注數據來訓練分類和回歸模型","隨機森林是一種集成學習方法,常用于分類任務","特征工程是機器學習中提升模型性能的關鍵步驟","支持向量機(SVM)適用于高維數據的分類問題","交叉驗證技術用于評估機器學習模型的泛化能力","梯度下降法是優化機器學習模型參數的常用方法","K近鄰算法基于數據點的距離進行分類或回歸","貝葉斯分類器利用概率統計實現高效的文本分類","機器學習中的過擬合問題可通過正則化技術緩解",# DL類"深度學習通過多層神經網絡模擬人腦的信息處理方式","卷積神經網絡(CNN)在圖像識別任務中表現出色","循環神經網絡(RNN)擅長處理時序數據和自然語言","生成對抗網絡(GAN)可用于生成逼真的圖像和文本","Transformer模型推動了自然語言處理領域的突破","深度學習需要大量數據和計算資源進行模型訓練","注意力機制提升了深度學習模型對關鍵信息的捕捉能力","遷移學習在深度學習中廣泛應用于小樣本場景","深度強化學習被用于訓練機器人完成復雜任務","神經網絡的參數調優對深度學習模型性能至關重要"
]labels = ['AI'] * 10 + ['ML'] * 10 + ['DL'] * 10 # 生成對應標簽
手搓版本
class TextClassifier(TFIDFBase):def __init__(self, corpus, labels):super().__init__(corpus)self.labels = labelsself.class_vectors = self._build_class_vectors()def _build_class_vectors(self):"""按類別聚合 TF-IDF 向量(簡單平均)"""class_vectors = defaultdict(list)tfidf_vectors = self.get_tfidf_vector()for label, tfidf in zip(self.labels, tfidf_vectors):class_vectors[label].append(tfidf)# 計算類別向量(平均)avg_class_vectors = {}for label, vectors in class_vectors.items():avg_vector = defaultdict(float)count = len(vectors)for vec in vectors:for token, val in vec.items():avg_vector[token] += val / countavg_class_vectors[label] = avg_vectorreturn avg_class_vectorsdef classify(self, text):"""對新文本分類(余弦相似度)"""tokens = preprocess(text)tf = self.compute_tf(tokens)tfidf = self.compute_tfidf(tf)# 計算余弦相似度def cosine_sim(vec1, vec2):common_tokens = set(vec1.keys()) & set(vec2.keys())dot = sum(vec1[t] * vec2[t] for t in common_tokens)norm1 = math.sqrt(sum(v ** 2 for v in vec1.values()))norm2 = math.sqrt(sum(v ** 2 for v in vec2.values()))return dot / (norm1 * norm2 + 1e-8)max_sim = -1predicted_label = Nonefor label, class_vec in self.class_vectors.items():sim = cosine_sim(tfidf, class_vec)if sim > max_sim:max_sim = simpredicted_label = labelreturn predicted_label
執行
new_text = "強化學習是人工智能的前沿領域"classifier = TextClassifier(corpus, labels)
print(f"Classified Label: {classifier.classify(new_text)}")
結果
Classified Label: AI
依賴版本
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report# 使用TF - IDF向量化器
vectorizer = TfidfVectorizer(tokenizer=preprocess, # 指定自定義分詞函數token_pattern=r"(?u)\b\w+\b", # 匹配中文分詞結果(可忽略)max_features=1000 # 控制詞匯表大小
)
執行
# 將文本轉換為TF-IDF特征向量
X = vectorizer.fit_transform(corpus)
y = np.array(labels)# 劃分訓練集和測試集(由于樣本太少,此處僅演示流程)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 訓練分類模型(以邏輯回歸為例)
model = LogisticRegression()
model.fit(X_train, y_train)# 預測與評估
# 使用訓練好的TF-IDF向量化器轉換新文本
X_new = vectorizer.transform([new_text])
y_pred = model.predict(X_new)
print("分類標簽:", y_pred)
結果
分類標簽: ['AI']
TF-IDF 信息檢索
手搓版本
class InformationRetriever(TFIDFBase):def __init__(self, corpus):super().__init__(corpus)self.tfidf_matrix = self._build_tfidf_matrix()def _build_tfidf_matrix(self):"""構建 TF-IDF 矩陣(文檔向量化)"""tfidf_vectors = self.get_tfidf_vector()# 構建全局詞表self.vocab = {token: idx for idx, token in enumerate(set(token for vec in tfidf_vectors for token in vec))}# 轉換為 NumPy 矩陣matrix = np.zeros((self.N, len(self.vocab)))for i, vec in enumerate(tfidf_vectors):for token, val in vec.items():matrix[i, self.vocab[token]] = valreturn matrixdef search(self, query, top_k=2):"""根據查詢語句檢索最相關文檔"""# 預處理查詢tokens = preprocess(query)tf = self.compute_tf(tokens)tfidf = self.compute_tfidf(tf)# 構建查詢向量query_vec = np.zeros(len(self.vocab))for token, val in tfidf.items():if token in self.vocab:query_vec[self.vocab[token]] = val# 計算余弦相似度sims = []for i in range(self.N):doc_vec = self.tfidf_matrix[i]sim = np.dot(query_vec, doc_vec) / (np.linalg.norm(query_vec) * np.linalg.norm(doc_vec) + 1e-8)sims.append((i, sim))# 返回 top-k 相關文檔return [self.corpus[i] for i, _ in sorted(sims, key=lambda x: -x[1])[:top_k]]
執行
corpus = ["自然語言處理是人工智能的一個重要分支","機器學習方法在自然語言處理中起著關鍵作用","深度學習技術推動了自然語言處理的發展","計算機視覺是人工智能領域的重要研究方向之一","強化學習是人工智能的前沿領域"
]
# "信息檢索"
query = "人工智能和機器學習的關系"
retriever = InformationRetriever(corpus)
results = retriever.search(query, top_k=3)
for idx, r in enumerate(results):print(f"Matched Document {idx}: {r}")
結果
Matched Document 0: 機器學習方法在自然語言處理中起著關鍵作用
Matched Document 1: 強化學習是人工智能的前沿領域
Matched Document 2: 自然語言處理是人工智能的一個重要分支
依賴版本
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity# 使用TF-IDF向量化器
vectorizer = TfidfVectorizer(tokenizer=preprocess, # 自定義分詞函數token_pattern=r"(?u)\b\w+\b", # 對中文無效,但不影響max_features=1000 # 控制詞匯表大小
)
執行
# 將語料庫轉換為TF-IDF特征向量
X_corpus = vectorizer.fit_transform(corpus)# 示例查詢
query = "人工智能和機器學習的關系"# 預處理并轉換查詢
X_query = vectorizer.transform([query]) # 注意:必須用列表包裹# 計算余弦相似度
similarities = cosine_similarity(X_query, X_corpus)# 輸出最相關的文檔
top_n = 3 # 返回前3個最相關文檔
top_indices = np.argsort(similarities[0])[::-1][:top_n] # 降序排序取索引print("查詢:", query)
print("最相關的文檔:")
for idx in top_indices:print(f"文檔 {idx + 1}: {corpus[idx]} (相似度: {similarities[0][idx]:.4f})")
結果
查詢: 人工智能和機器學習的關系
最相關的文檔:
文檔 2: 機器學習方法在自然語言處理中起著關鍵作用 (相似度: 0.4752)
文檔 5: 強化學習是人工智能的前沿領域 (相似度: 0.3458)
文檔 1: 自然語言處理是人工智能的一個重要分支 (相似度: 0.1913)
結語
通過本文的實踐,我們不僅驗證了TF-IDF算法的實用性,更展示了它在關鍵詞提取、文本分類和信息檢索中的多樣化應用場景。
當然,TF-IDF并非萬能鑰匙:它無法捕捉詞序、上下文語義,對動態語境和復雜任務的支持有限。但正如我們所見,它依然是許多現代算法(如BM25、深度學習模型)的重要基礎。
關于我
TFIDF #關鍵詞抽取 #文本分類 #信息檢索 # 文本匹配