导航菜单

  • 1.vector
  • 2.milvus
  • 3.pymilvus
  • 4.rag
  • 5.rag_measure
  • ragflow
  • heapq
  • HNSW
  • cosine_similarity
  • math
  • typing
  • etcd
  • minio
  • collections
  • jieba
  • random
  • beautifulsoup4
  • chromadb
  • sentence_transformers
  • numpy
  • lxml
  • openpyxl
  • PyMuPDF
  • python-docx
  • requests
  • python-pptx
  • text_splitter
  • all-MiniLM-L6-v2
  • openai
  • llm
  • BPETokenizer
  • Flask
  • RAGAS
  • BagofWords
  • langchain
  • Pydantic
  • abc
  • faiss
  • MMR
  • scikit-learn
  • Runnable
  • PromptEngineering
  • dataclasses
  • LaTeX
  • rank_bm25
  • TF-IDF
  • asyncio
  • sqlalchemy
  • fastapi
  • Starlette
  • uvicorn
  • argparse
  • Generic
  • ssl
  • urllib
  • python-dotenv
  • RRF
  • CrossEncoder
  • Lost-in-the-middle
  • Jinja2
  • logger
  • io
  • venv
  • concurrent
  • parameter
  • SSE
  • 1. 什么是 TF-IDF?
    • 1.1 简单理解
    • 1.2 为什么需要 TF-IDF?
    • 1.3 应用场景
  • 2. 前置知识
    • 2.1 词频(Term Frequency, TF)
    • 2.2 文档频率(Document Frequency, DF)
    • 2.3 逆文档频率(Inverse Document Frequency, IDF)
    • 2.4 对数(Logarithm)
    • 2.5 词袋模型(Bag of Words)
    • 2.6 Python 基础知识
  • 3. TF-IDF 的核心思想
    • 3.1 TF(词频)的作用
    • 3.2 IDF(逆文档频率)的作用
    • 3.3 TF-IDF 的组合
  • 4.TF-IDF 的计算公式
    • 4.1 TF(词频)的计算
    • 4.2 IDF(逆文档频率)的计算
    • 4.3 TF-IDF 的计算
  • 5. 计算文档TF-IDF向量
    • 5.1 代码实现
    • 5.2 执行过程
    • 5.3 执行流程图
    • 5.4 关键点总结
  • 6. 实际应用示例
    • 6.1 文档相似度计算
    • 6.2 关键词提取
  • 7.TF-IDF 的优缺点
    • 7.1 优点
    • 7.2 缺点
  • 8.常见问题
    • 8.1 TF-IDF 值越大越好吗?
    • 8.2 如何处理中文文档?
    • 8.3 TF-IDF 和词频(TF)有什么区别?
    • 8.4 如何选择 TF 和 IDF 的计算方法?
    • 8.5 TF-IDF 适合多大规模的数据?
  • 9. 总结

1. 什么是 TF-IDF? #

  • TF-IDF TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)是信息检索和文本挖掘中常用的加权技术,用于评估一个词语在文档集中的重要性。

1.1 简单理解 #

想象你在图书馆找关于"机器学习"的书:

  • TF(词频):某本书中"机器学习"这个词出现得越多,这本书可能越相关
  • IDF(逆文档频率):如果"机器学习"这个词只在少数几本书中出现,说明它很有区分度;如果每本书都有这个词,说明它很普通,区分度低
  • TF-IDF:综合考虑这两个因素,找出真正重要的词

TF-IDF 的核心思想:一个词在一篇文档中出现的频率高(TF 高),但在整个文档集合中出现的频率低(IDF 高),则这个词具有很好的区分能力,适合作为关键词。

1.2 为什么需要 TF-IDF? #

在文本处理中,我们需要:

  1. 找出重要词汇:哪些词最能代表文档的内容?
  2. 过滤常见词:像"的"、"是"、"在"这样的词虽然出现频繁,但对区分文档没有帮助
  3. 量化词语重要性:给每个词一个数值,表示它的重要性

TF-IDF 就是解决这些问题的经典方法。

1.3 应用场景 #

TF-IDF 广泛应用于:

  • 搜索引擎:计算查询词与文档的相关性
  • 文本相似度:将文档转为 TF-IDF 向量,用余弦相似度比较
  • 关键词提取:选取 TF-IDF 值最高的词作为关键词
  • 文档分类/聚类:作为特征输入机器学习模型
  • 自动摘要:识别文档中的重要句子

2. 前置知识 #

在学习 TF-IDF 之前,我们需要了解一些基础概念:

2.1 词频(Term Frequency, TF) #

词频是指一个词在文档中出现的次数。

示例:

  • 文档:"我喜欢机器学习,机器学习很有趣"
  • "机器学习"出现 2 次,TF("机器学习") = 2
  • "我"出现 1 次,TF("我") = 1

直觉:一个词在文档中出现次数越多,该文档可能与该词越相关。

2.2 文档频率(Document Frequency, DF) #

文档频率是指包含某个词的文档数量。

示例:

  • 文档集合中有 100 篇文档
  • 其中 5 篇包含"机器学习",则 DF("机器学习") = 5
  • 其中 80 篇包含"的",则 DF("的") = 80

直觉:一个词在越少的文档中出现,它越能区分文档(如"机器学习"比"的"更有区分度)。

2.3 逆文档频率(Inverse Document Frequency, IDF) #

逆文档频率是文档频率的倒数,用于衡量词的稀有程度。

公式: $$ \text{IDF}(词) = \log\left(\frac{\text{总文档数}}{\text{包含该词的文档数}}\right) $$

示例:

  • 总文档数 = 100
  • DF("机器学习") = 5,则 IDF("机器学习") = log(100/5) = log(20) ≈ 3.0
  • DF("的") = 80,则 IDF("的") = log(100/80) = log(1.25) ≈ 0.22

直觉:IDF 越大,表示词越稀有,越能区分文档。

2.4 对数(Logarithm) #

对数是数学中的一种运算,用于处理大数值的缩放。

常用对数:

  • log(10) = 1
  • log(100) = 2
  • log(1000) = 3
  • log(1) = 0

为什么使用对数?

  • 压缩数值范围:避免 IDF 值过大
  • 符合信息论:信息量与对数成正比

Python 中的对数:

import math
math.log(10)  # 自然对数(以 e 为底)
math.log10(10)  # 常用对数(以 10 为底)

2.5 词袋模型(Bag of Words) #

词袋模型是一种文本表示方法,将文档看作词的集合,忽略词序和语法。

示例:

  • 文档 1:"我喜欢机器学习"
  • 文档 2:"机器学习很有趣"

词袋表示:

  • 文档 1:{"我": 1, "喜欢": 1, "机器学习": 1}
  • 文档 2:{"机器学习": 1, "很": 1, "有趣": 1}

特点:

  • 简单有效
  • 忽略词序("我喜欢"和"喜欢我"被视为相同)
  • 忽略语法结构

2.6 Python 基础知识 #

需要了解:

  • 列表(list):用于存储文档和词
  • 字典(dict):用于存储词频、文档频率等统计信息
  • 字符串操作:分词、计数等
  • 数学函数:log()(对数函数)、sum()(求和)

3. TF-IDF 的核心思想 #

TF-IDF 的核心思想是:一个词在文档中出现的次数越多,同时在整个文档集合中出现的次数越少,则该词对于该文档的重要性越高。

3.1 TF(词频)的作用 #

TF 衡量词在单篇文档中的重要性:

  • TF 高:词在文档中出现频繁,可能很重要
  • TF 低:词在文档中出现很少,可能不重要

示例:

  • 文档 A:"机器学习是人工智能的重要分支,机器学习应用广泛"
  • "机器学习"出现 2 次,TF 高,说明文档 A 与"机器学习"相关

3.2 IDF(逆文档频率)的作用 #

IDF 衡量词在整个文档集合中的稀有程度:

  • IDF 高:词只在少数文档中出现,区分能力强
  • IDF 低:词在很多文档中出现,区分能力弱

示例:

  • "机器学习"只在 5% 的文档中出现,IDF 高,是很好的关键词
  • "的"在 95% 的文档中出现,IDF 低,不是好的关键词

3.3 TF-IDF 的组合 #

TF-IDF = TF × IDF

组合效果:

  • TF 高 + IDF 高:完美关键词(如文档特有的专业术语)
  • TF 高 + IDF 低:常见但无区分度(如"的"、"是")
  • TF 低 + IDF 高:稀有但不重要(如拼写错误)
  • TF 低 + IDF 低:完全不重要

4.TF-IDF 的计算公式 #

4.1 TF(词频)的计算 #

TF 有多种计算方法,最常用的是标准化频率:

$$ \text{TF}(t, d) = \frac{\text{词 t 在文档 d 中出现的次数}}{\text{文档 d 的总词数}} $$

其他方法:

  • 原始计数:TF(t,d) = 词 t 在文档 d 中出现的次数
  • 对数缩放:TF(t,d) = log(1 + 原始计数)

示例:

  • 文档:"我喜欢机器学习,机器学习很有趣"(共 8 个词)
  • "机器学习"出现 2 次
  • TF("机器学习") = 2/8 = 0.25

4.2 IDF(逆文档频率)的计算 #

IDF 的标准公式:

$$ \text{IDF}(t) = \log\left(\frac{N}{n(t) + 1}\right) $$

其中:

  • $N$:文档集合中的总文档数
  • $n(t)$:包含词 t 的文档数
  • 加 1 是为了避免分母为零(平滑处理)

示例:

  • 总文档数 $N = 1000$
  • 包含"机器学习"的文档数 $n(\text{机器学习}) = 10$
  • IDF("机器学习") = log(1000/(10+1)) = log(90.9) ≈ 4.51

4.3 TF-IDF 的计算 #

$$ \text{TF-IDF}(t, d) = \text{TF}(t, d) \times \text{IDF}(t) $$

完整示例: 假设文档集合有 1000 篇文档,某文档 d 有 100 个词,"机器学习"出现 5 次:

  1. 计算 TF:

    • TF("机器学习", d) = 5/100 = 0.05
  2. 计算 IDF:

    • 假设有 10 篇文档包含"机器学习"
    • IDF("机器学习") = log(1000/(10+1)) ≈ 4.51
  3. 计算 TF-IDF:

    • TF-IDF("机器学习", d) = 0.05 × 4.51 ≈ 0.23

5. 计算文档TF-IDF向量 #

TF-IDF

5.1 代码实现 #

# 导入math库,用于数学运算
import math
# 导入Counter用于统计词频
from collections import Counter

# 定义TFIDF类
class TFIDF:
    # 初始化方法,传入文档集合
    def __init__(self, documents):
        """
        初始化 TF-IDF 模型

        参数:
            documents: 文档列表,每个文档是一个词列表
        """
        # 保存文档集合,每个文档是单词列表
        self.documents = documents

        # 计算文档总数
        self.N = len(documents)

        # 定义词-文档频率(DF)字典
        self.df = {}

        # 遍历每个文档
        for doc in documents:
            # 获取当前文档中所有唯一词(去重)
            unique_words = set(doc)

            # 遍历文档中的每个唯一单词
            for word in unique_words:
                # 如果词未出现在df中,返回0并加1,否则直接加1
                self.df[word] = self.df.get(word, 0) + 1

        # 定义词-IDF值字典
        self.idf = {}

        # 遍历每个词及其对应DF值
        for word, df_value in self.df.items():
            # 计算IDF值,采用log(N/(df+1))避免分母为0
            self.idf[word] = math.log(self.N / (df_value + 1))

    # 计算某个词在某一文档中的词频(TF)
    def calculate_tf(self, word, doc):
        """
        计算词在文档中的词频(TF)

        参数:
            word: 词
            doc: 文档(词的列表)

        返回:
            词频(标准化频率)
        """
        # 如果文档为空,直接返回0
        if len(doc) == 0:
            return 0

        # 统计文档中每个词出现的次数
        word_counts = Counter(doc)

        # 获取目标词出现的次数
        word_count = word_counts.get(word, 0)

        # 计算词频:出现次数/文档长度
        tf = word_count / len(doc)

        # 返回tf值
        return tf

    # 计算某个词在某一文档中的TF-IDF值
    def calculate_tfidf(self, word, doc):
        """
        计算词的 TF-IDF 值

        参数:
            word: 词
            doc: 文档(词的列表)

        返回:
            TF-IDF 值
        """
        # 先计算词频TF
        tf = self.calculate_tf(word, doc)

        # 如果该词不在IDF词典中,返回0(没在所有文档中出现过)
        if word not in self.idf:
            return 0

        # 获取该词的IDF值
        idf = self.idf[word]

        # 计算TF-IDF值
        tfidf = tf * idf

        # 返回TF-IDF结果
        return tfidf

    # 获取文档的TF-IDF向量(仅包含出现的词)
    def get_tfidf_vector(self, doc):
        """
        获取文档的 TF-IDF 向量

        参数:
            doc: 文档(词的列表)

        返回:
            字典,键为词,值为 TF-IDF 值
        """
        # 定义用于存放向量的字典
        vector = {}

        # 获取文档中所有唯一词
        unique_words = set(doc)

        # 遍历每个词,计算TF-IDF值存入字典
        for word in unique_words:
            vector[word] = self.calculate_tfidf(word, doc)

        # 返回字典
        return vector

    # 获取文档中TF-IDF值最大的前k个关键词
    def get_top_keywords(self, doc, top_k=10):
        """
        获取文档中 TF-IDF 值最高的前 k 个词(关键词)

        参数:
            doc: 文档(词的列表)
            top_k: 返回的关键词数量

        返回:
            关键词列表(按 TF-IDF 值降序排列)
        """
        # 获取当前文档的TF-IDF字典向量
        vector = self.get_tfidf_vector(doc)

        # 对词按照TF-IDF值降序排序
        sorted_words = sorted(vector.items(), key=lambda x: x[1], reverse=True)

        # 取出前k个关键词
        top_keywords = [word for word, score in sorted_words[:top_k]]

        # 返回关键词列表
        return top_keywords

# 定义文档数据,每个文档是词的列表
documents = [
    ["我", "喜欢", "机器学习"],
    ["机器学习", "很", "有趣"],
    ["自然语言处理", "是", "AI", "的", "重要", "分支"]
]

# 创建TFIDF对象
tfidf = TFIDF(documents)
# 获取整个词汇表,并排序,便于统一向量顺序
vocabulary = sorted(tfidf.df.keys())
print(vocabulary)
# 计算所有文档的稀疏TF-IDF向量(字典形式)
sparse_vectors = [tfidf.get_tfidf_vector(doc) for doc in documents]
print(sparse_vectors)
# 初始化完整向量列表
full_vectors = []
# 对每个文档构造完整的向量(所有词都占一个维度,不出现则为0)
for sparse_vector in sparse_vectors:
    # 存放当前文档完整向量
    vec = []
    # 按词汇表顺序补足0
    for word in vocabulary:
        vec.append(sparse_vector.get(word, 0.0))
    # 将当前文档向量加入总列表
    full_vectors.append(vec)
# 打印所有文档的完整TF-IDF向量
print(full_vectors)

5.2 执行过程 #

阶段 1:导入库和定义类

import math
from collections import Counter

class TFIDF:
    # ... 类定义
  • 导入 math 用于对数计算
  • 导入 Counter 用于词频统计
  • 定义 TFIDF 类

阶段 2:准备数据

documents = [
    ["我", "喜欢", "机器学习"],
    ["机器学习", "很", "有趣"],
    ["自然语言处理", "是", "AI", "的", "重要", "分支"]
]
  • 定义 3 个文档,每个文档是词列表

阶段 3:创建 TFIDF 对象

tfidf = TFIDF(documents)

执行 __init__ 方法:

步骤 3.1:保存文档集合

self.documents = documents
self.N = 3  # 文档总数

步骤 3.2:计算文档频率 DF

遍历每个文档,统计每个词出现在多少个文档中:

# 文档1: ["我", "喜欢", "机器学习"]
#   "我" → df["我"] = 1
#   "喜欢" → df["喜欢"] = 1
#   "机器学习" → df["机器学习"] = 1

# 文档2: ["机器学习", "很", "有趣"]
#   "机器学习" → df["机器学习"] = 1 + 1 = 2  (已存在,加1)
#   "很" → df["很"] = 1
#   "有趣" → df["有趣"] = 1

# 文档3: ["自然语言处理", "是", "AI", "的", "重要", "分支"]
#   "自然语言处理" → df["自然语言处理"] = 1
#   "是" → df["是"] = 1
#   "AI" → df["AI"] = 1
#   "的" → df["的"] = 1
#   "重要" → df["重要"] = 1
#   "分支" → df["分支"] = 1

最终 df 字典:

{
    "我": 1,
    "喜欢": 1,
    "机器学习": 2,  # 出现在2个文档中
    "很": 1,
    "有趣": 1,
    "自然语言处理": 1,
    "是": 1,
    "AI": 1,
    "的": 1,
    "重要": 1,
    "分支": 1
}

步骤 3.3:计算 IDF 值

对每个词计算 IDF = log(N / (df + 1)):

# 对于 "我": IDF = log(3 / (1 + 1)) = log(1.5) ≈ 0.4055
# 对于 "机器学习": IDF = log(3 / (2 + 1)) = log(1) = 0.0000
# 对于 "AI": IDF = log(3 / (1 + 1)) = log(1.5) ≈ 0.4055
# ... 其他词类似

最终 idf 字典:

{
    "我": 0.4055,
    "喜欢": 0.4055,
    "机器学习": 0.0000,  # 很常见,IDF低
    "很": 0.4055,
    "有趣": 0.4055,
    "自然语言处理": 0.4055,
    "是": 0.4055,
    "AI": 0.4055,
    "的": 0.4055,
    "重要": 0.4055,
    "分支": 0.4055
}

阶段 4:获取词汇表

vocabulary = sorted(tfidf.df.keys())
print(vocabulary)
  • 获取所有词并排序,用于统一向量顺序
  • 输出:['AI', '分支', '喜欢', '很', '的', '是', '有趣', '机器学习', '我', '自然语言处理', '重要']

阶段 5:计算所有文档的稀疏向量

sparse_vectors = [tfidf.get_tfidf_vector(doc) for doc in documents]
print(sparse_vectors)

对每个文档调用 get_tfidf_vector:

文档1:["我", "喜欢", "机器学习"]

# 1. 获取唯一词: {"我", "喜欢", "机器学习"}
# 2. 对每个词计算 TF-IDF:

# "我":
#   - TF = 1/3 = 0.3333
#   - IDF = 0.4055
#   - TF-IDF = 0.3333 × 0.4055 = 0.1352

# "喜欢":
#   - TF = 1/3 = 0.3333
#   - IDF = 0.4055
#   - TF-IDF = 0.3333 × 0.4055 = 0.1352

# "机器学习":
#   - TF = 1/3 = 0.3333
#   - IDF = 0.0000
#   - TF-IDF = 0.3333 × 0.0000 = 0.0000

文档1的稀疏向量:

{"我": 0.1352, "喜欢": 0.1352, "机器学习": 0.0000}

文档2:["机器学习", "很", "有趣"]

# "机器学习": TF=1/3=0.3333, IDF=0.0000, TF-IDF=0.0000
# "很": TF=1/3=0.3333, IDF=0.4055, TF-IDF=0.1352
# "有趣": TF=1/3=0.3333, IDF=0.4055, TF-IDF=0.1352

文档2的稀疏向量:

{"机器学习": 0.0000, "很": 0.1352, "有趣": 0.1352}

文档3:["自然语言处理", "是", "AI", "的", "重要", "分支"]

# 每个词: TF=1/6=0.1667, IDF=0.4055, TF-IDF=0.1667×0.4055=0.0676

文档3的稀疏向量:

{"自然语言处理": 0.0676, "是": 0.0676, "AI": 0.0676, 
 "的": 0.0676, "重要": 0.0676, "分支": 0.0676}

最终 sparse_vectors:

[
    {"我": 0.1352, "喜欢": 0.1352, "机器学习": 0.0000},
    {"机器学习": 0.0000, "很": 0.1352, "有趣": 0.1352},
    {"自然语言处理": 0.0676, "是": 0.0676, "AI": 0.0676, 
     "的": 0.0676, "重要": 0.0676, "分支": 0.0676}
]

阶段 6:转换为完整向量

full_vectors = []
for sparse_vector in sparse_vectors:
    vec = []
    for word in vocabulary:  # 按词汇表顺序
        vec.append(sparse_vector.get(word, 0.0))  # 存在则取值,不存在则为0
    full_vectors.append(vec)

按词汇表顺序,将稀疏向量扩展为完整向量:

文档1的完整向量:

# vocabulary = ['AI', '分支', '喜欢', '很', '的', '是', '有趣', '机器学习', '我', '自然语言处理', '重要']
# sparse_vector = {"我": 0.1352, "喜欢": 0.1352, "机器学习": 0.0000}

vec = [
    0.0000,  # 'AI' (不存在)
    0.0000,  # '分支' (不存在)
    0.1352,  # '喜欢' (存在)
    0.0000,  # '很' (不存在)
    0.0000,  # '的' (不存在)
    0.0000,  # '是' (不存在)
    0.0000,  # '有趣' (不存在)
    0.0000,  # '机器学习' (存在,但值为0)
    0.1352,  # '我' (存在)
    0.0000,  # '自然语言处理' (不存在)
    0.0000   # '重要' (不存在)
]

文档2和文档3类似处理

最终 full_vectors:

[
    [0.0, 0.0, 0.1352, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1352, 0.0, 0.0],  # 文档1
    [0.0, 0.0, 0.0, 0.1352, 0.0, 0.0, 0.1352, 0.0, 0.0, 0.0, 0.0],  # 文档2
    [0.0676, 0.0676, 0.0, 0.0, 0.0676, 0.0676, 0.0, 0.0, 0.0, 0.0676, 0.0676]  # 文档3
]

5.3 执行流程图 #

定义文档集合
    ↓
创建 TFIDF 对象
    ↓
【初始化阶段】
  ├─ 计算文档频率 DF
  └─ 计算 IDF 值
    ↓
获取词汇表(排序)
    ↓
【向量化阶段】
  ├─ 对每个文档计算稀疏向量
  │   ├─ 计算每个词的 TF
  │   ├─ 获取每个词的 IDF
  │   └─ 计算 TF-IDF = TF × IDF
  └─ 转换为完整向量
    ↓
输出结果

5.4 关键点总结 #

  1. 初始化时计算全局的 DF 和 IDF
  2. 每个文档的 TF 是文档特定的
  3. 稀疏向量只包含文档中出现的词
  4. 完整向量按词汇表顺序,缺失词用 0 填充
  5. 所有文档的向量维度相同(等于词汇表大小)

6. 实际应用示例 #

6.1 文档相似度计算 #

使用 TF-IDF 向量计算文档之间的相似度:

# 导入必要的库
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import jieba

# 定义中文分词函数
def chinese_tokenizer(text):
    """使用 jieba 进行中文分词"""
    return " ".join(jieba.cut(text))

# 定义文档集合
documents = [
    "我喜欢机器学习",
    "机器学习很有趣",
    "自然语言处理是AI的重要分支",
    "我喜欢编程"
]

# 创建 TF-IDF 向量化器,使用中文分词器
vectorizer = TfidfVectorizer(tokenizer=chinese_tokenizer)

# 将文档转换为 TF-IDF 矩阵(训练向量化器)
tfidf_matrix = vectorizer.fit_transform(documents)

# 定义新文档
new_document = "我对深度学习和人工智能很感兴趣"

# 将新文档转换为 TF-IDF 向量(使用已训练的 vectorizer)
# transform 方法使用 fit 时学到的词汇表和 IDF 值
new_doc_vector = vectorizer.transform([new_document])

# 计算新文档与所有文档的余弦相似度
# cosine_similarity 返回一个矩阵,[0] 取第一行(新文档与所有文档的相似度)
similarities = cosine_similarity(new_doc_vector, tfidf_matrix)[0]

# 获取相似度最高的2个文档的索引
# argsort 返回排序后的索引,[::-1] 反转得到降序,[:2] 取前2个
top_2_indices = np.argsort(similarities)[::-1][:2]

for rank, idx in enumerate(top_2_indices, 1):
    similarity_score = similarities[idx]
    print(f"\n排名 {rank}:")
    print(f"  文档编号: D{idx+1}")
    print(f"  相似度: {similarity_score:.4f}")
    print(f"  文档内容: {documents[idx]}")

6.2 关键词提取 #

从文档中提取最重要的关键词:

# 导入sklearn中的TfidfVectorizer用于TF-IDF计算
from sklearn.feature_extraction.text import TfidfVectorizer
# 导入numpy用于数值运算和排序
import numpy as np
# 导入jieba用于中文分词
import jieba

# 定义待处理的中文文档
document = "机器学习是人工智能的重要分支,机器学习应用广泛,包括自然语言处理和计算机视觉"

# 创建TF-IDF向量化器,设置最多保留10个特征词,仅使用1-gram(即单个词)
vectorizer = TfidfVectorizer(
    max_features=10,  # 最多保留10个特征词
    ngram_range=(1, 1)  # 仅考虑单个词
)

# 使用jieba对中文文档进行分词
words = jieba.cut(document)
# 用空格拼接分词结果,供向量化器处理
doc_text = " ".join(words)
# 训练TF-IDF向量化器,并将文档转换成TF-IDF向量
tfidf_vector = vectorizer.fit_transform([doc_text])

# 获取所有特征词(即词汇表中被保留的词)
feature_names = vectorizer.get_feature_names_out()
# 获取文档对应的TF-IDF值,并转换为一维数组
tfidf_scores = tfidf_vector.toarray()[0]

# 对TF-IDF分数进行降序排序,得到排序后的索引
sorted_indices = np.argsort(tfidf_scores)[::-1]

# 打印待分析的文档内容
print(f"文档: {document}")
# 输出前5个关键词
print("\n关键词(Top 5):")
for i, idx in enumerate(sorted_indices[:5], 1):
    # 获取排序后的特征词
    word = feature_names[idx]
    # 获取对应的TF-IDF得分
    score = tfidf_scores[idx]
    # 打印关键词及对应的TF-IDF分值
    print(f"  {i}. {word} (TF-IDF: {score:.4f})")

7.TF-IDF 的优缺点 #

7.1 优点 #

  1. 简单有效:算法简单,容易理解和实现
  2. 计算高效:计算速度快,适合大规模文档处理
  3. 过滤常见词:IDF 部分可以自动过滤停用词(如"的"、"是")
  4. 无监督方法:不需要标注数据,可以直接使用
  5. 解释性强:每个词的 TF-IDF 值都有明确的含义

7.2 缺点 #

  1. 忽略词序:基于词袋模型,不考虑词的顺序

    • 例如:"我喜欢你"和"你喜欢我"被视为相同
  2. 忽略语义:只考虑字面匹配,不考虑语义

    • 例如:"汽车"和"车辆"被视为不同
    • 例如:"苹果"(水果)和"苹果"(公司)无法区分
  3. 偏好长文档:长文档中词频容易高,可能获得不公平的优势

  4. 无法处理未登录词:如果词不在文档集合中出现,无法计算 TF-IDF

  5. 不能捕捉上下文:不考虑词的上下文信息

8.常见问题 #

8.1 TF-IDF 值越大越好吗? #

不一定。TF-IDF 值表示词的重要性,但需要结合具体任务:

  • 关键词提取:选择 TF-IDF 值最高的词
  • 文档相似度:使用 TF-IDF 向量计算相似度
  • 文档分类:作为特征输入分类器

8.2 如何处理中文文档? #

对于中文文档,需要先进行分词:

# 使用 jieba 进行中文分词
import jieba
from sklearn.feature_extraction.text import TfidfVectorizer

# 中文文档
documents = [
    "我喜欢机器学习",
    "机器学习很有趣",
    "自然语言处理是AI的重要分支"
]

# 分词处理
tokenized_docs = [" ".join(jieba.cut(doc)) for doc in documents]

# 创建 TF-IDF 向量化器
vectorizer = TfidfVectorizer()

# 转换为 TF-IDF 矩阵
tfidf_matrix = vectorizer.fit_transform(tokenized_docs)

8.3 TF-IDF 和词频(TF)有什么区别? #

  • TF:只考虑词在单篇文档中的频率
  • TF-IDF:同时考虑词在单篇文档中的频率和在整个文档集合中的稀有程度

示例:

  • "的"在文档中 TF 很高,但 IDF 很低(因为很多文档都有),所以 TF-IDF 不高
  • "机器学习"在文档中 TF 较高,IDF 也较高(因为只有少数文档有),所以 TF-IDF 较高

8.4 如何选择 TF 和 IDF 的计算方法? #

TF 计算方法:

  • 标准化频率(最常用):TF = 词频 / 文档总词数
  • 原始计数:简单但受文档长度影响
  • 对数缩放:压缩大值的影响

IDF 计算方法:

  • 标准公式:IDF = log(N / (df + 1))
  • 加 1 是为了避免分母为零(平滑处理)

大多数情况下,使用标准方法即可。

8.5 TF-IDF 适合多大规模的数据? #

TF-IDF 适合:

  • 小规模:几千到几万文档(单机即可)
  • 中规模:几十万到几百万文档(需要优化,如稀疏矩阵)
  • 大规模:千万级以上文档(需要分布式系统)

性能优化:

  • 使用稀疏矩阵存储(scikit-learn 默认)
  • 限制特征数量(max_features 参数)
  • 过滤停用词(max_df 参数)

9. 总结 #

TF-IDF 是文本处理领域的经典方法,虽然简单,但在许多实际应用中仍然非常有效。

核心特点:

  1. 简单有效:算法简单,容易理解和实现
  2. 计算高效:适合大规模文档处理
  3. 无监督:不需要标注数据
  4. 解释性强:每个值都有明确的含义

适用场景:

  • 搜索引擎(计算查询与文档的相关性)
  • 文本相似度计算
  • 关键词提取
  • 文档分类/聚类(作为特征)

使用建议:

  1. 对于大多数场景,使用 scikit-learn 的 TfidfVectorizer 即可
  2. 中文文档需要先进行分词
  3. 根据任务需求调整参数(如 max_features、min_df、max_df)
  4. 可以结合其他方法(如词向量、深度学习)获得更好的效果
← 上一节 text_splitter 下一节 typing →

访问验证

请输入访问令牌

Token不正确,请重新输入