别再死记硬背公式了用Python和sklearn手撕TF-IDF5分钟搞懂核心原理每次看到TF-IDF的公式就头疼面试被问到为什么要取对数时哑口无言别担心今天我们就用几行Python代码和几个新闻标题带你从厨房小白秒变算法大厨——不背公式只讲为什么。1. 为什么我们需要TF-IDF想象你在整理一周的新闻标题股市今日大幅上涨今日气温创历史新高新能源汽车今日发布如果让你找出每篇的核心词股市、气温、新能源这些词显然比今日更重要。这就是TF-IDF要解决的问题——量化词语的重要性。传统词频统计的致命缺陷在于今日出现3次但它毫无信息量新能源只出现1次却是关键信息好的特征提取应该像优秀编辑既能发现高频词又能过滤水词2. 拆解TF-IDF的物理意义2.1 TF词频的陷阱与出路计算股市在第一句的TF值def compute_tf(word, document): words document.split() return words.count(word) / len(words) title1 股市 今日 大幅 上涨 print(compute_tf(股市, title1)) # 输出0.25但单纯TF会导致长文档中正常词频被稀释的、是等停用词干扰判断2.2 IDF给词语发稀有度勋章关键理解log背后的设计哲学import math def compute_idf(word, documents): doc_count sum(1 for doc in documents if word in doc) return math.log(len(documents) / (doc_count 1)) titles [股市 今日 大幅 上涨, 今日 气温 创 历史 新高, 新能源 汽车 今日 发布] print(compute_idf(今日, titles)) # 0.0太常见 print(compute_idf(新能源, titles)) # 1.098稀有词为什么是log因为防止IDF值爆炸增长文档数可能百万级更符合人类对稀有度的感知对数尺度3. 手把手实现TF-IDF3.1 从零开始造轮子class SimpleTFIDF: def __init__(self, docs): self.docs docs self.N len(docs) self.doc_freq {} # 统计每个词出现在多少文档中 for doc in docs: words set(doc.split()) for word in words: self.doc_freq[word] self.doc_freq.get(word, 0) 1 def score(self, word, doc): tf doc.split().count(word) / len(doc.split()) idf math.log(self.N / (self.doc_freq.get(word, 0) 1)) return tf * idf # 测试我们的实现 processor SimpleTFIDF(titles) print(股市的TF-IDF:, processor.score(股市, titles[0])) # 0.366 print(今日的TF-IDF:, processor.score(今日, titles[0])) # 0.03.2 用sklearn验证结果from sklearn.feature_extraction.text import TfidfVectorizer vec TfidfVectorizer(token_patternr(?u)\b\w\b) tfidf vec.fit_transform(titles) print(vec.vocabulary_) # 查看词表索引 print(tfidf[0].toarray()) # 第一句的TF-IDF向量对比发现股市在手工计算和sklearn中都是最高值今日得分均为0细微差异来自sklearn的归一化处理4. 实战中的常见误区4.1 TF-IDF高就一定是关键词看这个反例special_case [比特币 暴涨, 比特币 暴跌] processor SimpleTFIDF(special_case) print(processor.score(比特币, special_case[0])) # 0.0比特币TF-IDF为0但它显然是关键词这说明TF-IDF只适合区分文档集内的特征词当某个词在所有文档都出现时需要其他方法辅助4.2 中文处理的特殊技巧import jieba text 自然语言处理很有趣 words .join(jieba.cut(text)) # 输出自然 语言 处理 很 有趣 # 需要自定义tokenizer def chinese_tokenizer(text): return jieba.cut(text) vec TfidfVectorizer(tokenizerchinese_tokenizer)5. 进阶TF-IDF的现代变种5.1 平滑技巧对比方法公式适用场景原始IDFlog(N/df)小型语料库平滑IDFlog(N/(df1))1避免除零错误概率IDFlog((N-df)/df)长尾分布数据5.2 与深度学习的结合from gensim.models import TfidfModel from gensim.corpora import Dictionary # 构建词袋模型 docs [[股市, 今日, 上涨], [气温, 今日, 新高]] dct Dictionary(docs) corpus [dct.doc2bow(doc) for doc in docs] # 训练TF-IDF模型 model TfidfModel(corpus) print(model[corpus[0]]) # 输出各词的(TermID, TF-IDF)对这种实现方式更适合大规模语料方便与Word2Vec等嵌入模型结合