一、文本特征提取概述
在自然语言处理(NLP)和文本挖掘任务中,文本特征提取是将原始文本数据转换为机器学习模型可以理解的数值特征的关键步骤。scikit-learn提供了两种常用的文本特征提取方法:CountVectorizer(词频统计)和TfidfVectorizer(TF-IDF加权)。
二、CountVectorizer:词频统计
2.1 CountVectorizer原理
CountVectorizer将文本集合转换为词频矩阵,统计每个文档中每个词的出现次数。它执行以下步骤:
-
分词(Tokenization):将文本拆分为单词或n-gram
-
构建词汇表:收集所有文档中的所有唯一单词
-
生成词频矩阵:统计每个文档中每个单词的出现次数
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 参数调优技巧
-
停用词处理:使用
stop_words='english'
可以过滤常见英文停用词 -
n-gram范围:
ngram_range=(1,2)
可以同时捕获单词和短语 -
词汇表限制:
max_features=1000
只保留最常见的1000个词 -
文档频率过滤:
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))) + 1sublinear_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参数调优技巧
-
归一化选择:
norm='l2'
通常效果最好 -
平滑IDF:
smooth_idf=True
可以避免除零错误 -
次线性TF缩放:
sublinear_tf=True
使用1+log(tf)代替原始tf -
自定义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和bigrammax_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 jiebadef 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:
-
使用
max_features
限制特征数量 -
使用
min_df
和max_df
过滤罕见和常见词 -
考虑使用HashingVectorizer替代
-
使用内存映射或分批处理
七、总结
CountVectorizer和TfidfVectorizer是文本特征提取的基础工具,理解它们的原理和参数对于构建高效的文本处理流水线至关重要。在实际应用中:
-
对于简单的词频统计任务,使用CountVectorizer
-
对于需要考虑词重要性的任务(如分类、检索),使用TfidfVectorizer
-
根据具体任务调整参数,特别是停用词、n-gram范围和文档频率过滤
-
结合后续的机器学习模型进行端到端的评估和调优
通过本教程,您应该能够熟练使用这两种文本特征提取方法,并为更复杂的NLP任务打下坚实基础。