机器学习文本特征提取:CountVectorizer与TfidfVectorizer详解

发布于:2025-07-03 ⋅ 阅读:(25) ⋅ 点赞:(0)

一、文本特征提取概述

在自然语言处理(NLP)和文本挖掘任务中,文本特征提取是将原始文本数据转换为机器学习模型可以理解的数值特征的关键步骤。scikit-learn提供了两种常用的文本特征提取方法:CountVectorizer(词频统计)和TfidfVectorizer(TF-IDF加权)。

二、CountVectorizer:词频统计

2.1 CountVectorizer原理

CountVectorizer将文本集合转换为词频矩阵,统计每个文档中每个词的出现次数。它执行以下步骤:

  1. 分词(Tokenization):将文本拆分为单词或n-gram

  2. 构建词汇表:收集所有文档中的所有唯一单词

  3. 生成词频矩阵:统计每个文档中每个单词的出现次数

2.2 CountVectorizer API详解

from sklearn.feature_extraction.text import CountVectorizer

# 初始化CountVectorizer
vectorizer = CountVectorizer(
    input='content',     # 输入类型,'content'表示输入为字符串或字节
    encoding='utf-8',    # 编码方式
    decode_error='strict',  # 解码错误处理方式
    strip_accents=None,  # 去除重音符号
    lowercase=True,      # 是否转换为小写
    preprocessor=None,   # 预处理函数
    tokenizer=None,      # 自定义分词器
    stop_words=None,     # 停用词列表
    token_pattern=r"(?u)\b\w\w+\b",  # 分词正则模式
    ngram_range=(1, 1),  # n-gram范围
    analyzer='word',     # 分析单位,'word'或'char'
    max_df=1.0,          # 忽略文档频率高于该阈值的词
    min_df=1,            # 忽略文档频率低于该阈值的词
    max_features=None,   # 最大特征数
    vocabulary=None,     # 自定义词汇表
    binary=False,        # 是否仅记录词是否出现而非频率
    dtype=np.int64       # 输出矩阵的数据类型
)

2.3 CountVectorizer示例代码 

from sklearn.feature_extraction.text import CountVectorizer

# 示例文本数据
corpus = [
    'This is the first document.',
    'This document is the second document.',
    'And this is the third one.',
    'Is this the first document?'
]

# 初始化CountVectorizer
vectorizer = CountVectorizer()

# 拟合数据并转换为词频矩阵
X = vectorizer.fit_transform(corpus)

# 查看词汇表
print("词汇表:", vectorizer.get_feature_names_out())
# 输出: ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

# 查看词频矩阵
print("词频矩阵:\n", X.toarray())
"""
输出:
[[0 1 1 1 0 0 1 0 1]
 [0 2 0 1 0 1 1 0 1]
 [1 0 0 1 1 0 1 1 1]
 [0 1 1 1 0 0 1 0 1]]
"""

# 对新文本进行转换
new_text = ["This is a new document."]
new_X = vectorizer.transform(new_text)
print("新文本词频:", new_X.toarray())
# 输出: [[0 1 0 1 0 0 0 0 1]]

2.4 参数调优技巧

  1. 停用词处理:使用stop_words='english'可以过滤常见英文停用词

  2. n-gram范围ngram_range=(1,2)可以同时捕获单词和短语

  3. 词汇表限制max_features=1000只保留最常见的1000个词

  4. 文档频率过滤min_df=2忽略只出现一次的单词

三、TfidfVectorizer:TF-IDF特征提取

3.1 TF-IDF原理

TF-IDF(Term Frequency-Inverse Document Frequency)是一种统计方法,用于评估一个词对于一个文档集或语料库中的其中一份文档的重要程度。其计算公式为:

TF-IDF = TF(t,d) × IDF(t) 

其中:

  • TF(t,d)是词t在文档d中的词频

  • IDF(t)是逆文档频率,计算公式为:IDF(t) = log(总文档数 / 包含词t的文档数) + 1

3.2 TfidfVectorizer API详解 

from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np

# 初始化TfidfVectorizer
vectorizer = TfidfVectorizer(
    # 输入参数设置
    input='content',     # 输入类型,可选'content'(默认)|'filename'|'file'
                        # 'content'表示直接输入文本内容,'filename'表示输入文件路径
    
    encoding='utf-8',    # 文本编码方式,默认utf-8,处理中文时通常保持默认
    
    decode_error='strict',  # 解码错误处理方式,可选'strict'|'ignore'|'replace'
                          # 'strict'遇到错误抛出异常;'ignore'忽略错误;'replace'用替换标记错误字符
    
    strip_accents=None,  # 去除重音符号,可选None|'ascii'|'unicode'
                       # None不处理;'ascii'快速处理;'unicode'精确处理但较慢
    
    lowercase=True,      # 是否将所有字符转换为小写,默认True
    
    # 预处理设置
    preprocessor=None,   # 自定义预处理函数,在分词前应用
                        # 例如: lambda x: x.replace('$', 'dollar')
    
    tokenizer=None,      # 自定义分词函数,覆盖默认的分词行为
                       # 例如中文分词: lambda x: jieba.cut(x)
    
    # 文本分析设置
    analyzer='word',     # 分析单位,可选'word'(默认)|'char'|'char_wb'
                       # 'word'按词分析;'char'按字符分析;'char_wb'按词边界内的字符分析
    
    stop_words=None,     # 停用词设置,可选None|'english'|list
                       # None无停用词;'english'使用内置英文停用词;list自定义停用词列表
    
    token_pattern=r"(?u)\b\w\w+\b",  # 分词正则表达式模式
                                    # 默认匹配至少2个字母数字字符的词
                                    # (?u)表示Unicode匹配模式,\b表示词边界
    
    ngram_range=(1, 1),  # n-gram范围,元组(min_n, max_n)
                        # (1,1)仅使用unigram;(1,2)使用unigram和bigram
    
    # 特征选择设置
    max_df=1.0,          # 忽略文档频率高于该阈值的词,float表示比例,int表示绝对数量
                       # 例如0.85表示忽略出现在85%以上文档中的词
    
    min_df=1,            # 忽略文档频率低于该阈值的词,同上
                       # 例如2表示忽略出现在少于2个文档中的词
    
    max_features=None,   # 最大特征数,按词频选择前N个特征
                       # None不限制;10000表示只保留最常见的10000个词
    
    vocabulary=None,     # 自定义词汇表,dict或可迭代对象
                       # 例如 {'apple':0, 'banana':1} 或 ['apple', 'banana']
    
    binary=False,        # 是否仅记录词是否出现而非频率
                       # True生成二进制特征;False(默认)使用实际词频
    
    # 输出设置
    dtype=np.float64,    # 输出矩阵的数据类型,通常np.float32或np.float64
    
    # TF-IDF特有参数
    norm='l2',          # 归一化方式,可选'l1'|'l2'|None
                       # 'l2'(默认)使用欧式范数;'l1'使用曼哈顿范数;None不归一化
    
    use_idf=True,       # 是否使用逆文档频率(IDF)权重,默认True
                       # 设为False则只使用TF(词频)部分
    
    smooth_idf=True,    # 是否平滑IDF权重,默认True
                       # 平滑避免除零错误,公式变为log(1+N/(1+df(t))) + 1
    
    sublinear_tf=False  # 是否应用次线性TF缩放,默认False
                       # True时使用1+log(tf)代替原始tf值
)

3.3 TfidfVectorizer示例代码 

from sklearn.feature_extraction.text import TfidfVectorizer

# 示例文本数据
corpus = [
    'This is the first document.',
    'This document is the second document.',
    'And this is the third one.',
    'Is this the first document?'
]

# 初始化TfidfVectorizer
tfidf_vectorizer = TfidfVectorizer()

# 拟合数据并转换为TF-IDF矩阵
X_tfidf = tfidf_vectorizer.fit_transform(corpus)

# 查看词汇表
print("词汇表:", tfidf_vectorizer.get_feature_names_out())
# 输出: ['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

# 查看TF-IDF矩阵
print("TF-IDF矩阵:\n", X_tfidf.toarray().round(2))
"""
输出:
[[0.   0.47 0.58 0.38 0.   0.   0.38 0.   0.38]
 [0.   0.69 0.   0.28 0.   0.54 0.28 0.   0.28]
 [0.51 0.   0.   0.27 0.51 0.   0.27 0.51 0.27]
 [0.   0.47 0.58 0.38 0.   0.   0.38 0.   0.38]]
"""

# 对新文本进行转换
new_text = ["This is a new document."]
new_X_tfidf = tfidf_vectorizer.transform(new_text)
print("新文本TF-IDF:", new_X_tfidf.toarray().round(2))
# 输出: [[0.   0.71 0.   0.5  0.   0.   0.   0.   0.5]]

3.4 TF-IDF参数调优技巧

  1. 归一化选择norm='l2'通常效果最好

  2. 平滑IDFsmooth_idf=True可以避免除零错误

  3. 次线性TF缩放sublinear_tf=True使用1+log(tf)代替原始tf

  4. 自定义IDF权重:可以通过TfidfTransformer自定义IDF计算

四、CountVectorizer与TfidfVectorizer对比

特性 CountVectorizer TfidfVectorizer
特征值类型 词频 TF-IDF权重
是否考虑词的重要性
稀疏矩阵
适用场景 简单词频分析 文本分类/检索
计算复杂度 较低 较高
归一化 通常有

五、实际应用案例:文本分类

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVC
from sklearn.metrics import classification_report

# 示例数据:正面和负面评论
texts = [
    "This movie is great!",
    "I love this product.",
    "Terrible experience.",
    "Worst service ever.",
    "Amazing performance!",
    "Not worth the money."
]
labels = [1, 1, 0, 0, 1, 0]  # 1:正面, 0:负面

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    texts, labels, test_size=0.3, random_state=42
)

# 使用TF-IDF进行特征提取
tfidf = TfidfVectorizer(
    stop_words='english',  # 移除英文停用词
    ngram_range=(1, 2),   # 使用unigram和bigram
    max_features=1000     # 限制特征数量
)

# 转换训练数据
X_train_tfidf = tfidf.fit_transform(X_train)

# 转换测试数据
X_test_tfidf = tfidf.transform(X_test)

# 训练分类器
clf = LinearSVC()
clf.fit(X_train_tfidf, y_train)

# 评估模型
y_pred = clf.predict(X_test_tfidf)
print(classification_report(y_test, y_pred))

六、常见问题解答

Q1:如何处理中文文本?
A1:中文需要先分词,可以使用jieba等分词工具,然后通过自定义tokenizer传入:

import jieba

def chinese_tokenizer(text):
    return jieba.lcut(text)

vectorizer = CountVectorizer(tokenizer=chinese_tokenizer)

Q2:如何保存和加载训练好的向量化器?
A2:可以使用joblib或pickle: 

import joblib

# 保存
joblib.dump(vectorizer, 'vectorizer.joblib')

# 加载
vectorizer = joblib.load('vectorizer.joblib')

Q3:如何处理大规模文本数据?
A3:

  1. 使用max_features限制特征数量

  2. 使用min_dfmax_df过滤罕见和常见词

  3. 考虑使用HashingVectorizer替代

  4. 使用内存映射或分批处理

七、总结

CountVectorizer和TfidfVectorizer是文本特征提取的基础工具,理解它们的原理和参数对于构建高效的文本处理流水线至关重要。在实际应用中:

  1. 对于简单的词频统计任务,使用CountVectorizer

  2. 对于需要考虑词重要性的任务(如分类、检索),使用TfidfVectorizer

  3. 根据具体任务调整参数,特别是停用词、n-gram范围和文档频率过滤

  4. 结合后续的机器学习模型进行端到端的评估和调优

通过本教程,您应该能够熟练使用这两种文本特征提取方法,并为更复杂的NLP任务打下坚实基础。

 

 

 

 

 

 

 

 

 

 

 

 


网站公告

今日签到

点亮在社区的每一天
去签到