趋近智
文本数值表示的一种实用方法是使用标准Python库,特别是scikit-learn,生成TF-IDF特征并加入N-gram。假设您已安装scikit-learn,并拥有一个可用的Python环境。
首先,我们导入必要的工具:来自scikit-learn的TfidfVectorizer。我们还将定义一个小样本语料库以便操作。
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
# 样本文档
corpus = [
"The quick brown fox jumps over the lazy dog.",
"The lazy dog slept in the sun.",
"The quick brown cat ran away.",
"Never jump over the lazy dog quickly!" # 添加变体
]
# 可选:显示语料库
print("样本语料库:")
for i, doc in enumerate(corpus):
print(f"文档 {i+1}: {doc}")
这个简单语料库包含四个短文档。我们的目标是将这些文本字符串转换为一个矩阵,其中行表示文档,列表示特征(经TF-IDF加权的词语)。
TfidfVectorizer将分词 (tokenization)、计数和TF-IDF转换组合为一个对象。我们来初始化它并将其拟合到我们的语料库。
# 1. 初始化TfidfVectorizer
# 默认设置:lowercase=True, token_pattern=r"(?u)\b\w\w+\b", stop_words=None, ngram_range=(1, 1)
tfidf_vectorizer = TfidfVectorizer()
# 2. 将向量器拟合到语料库并转换数据
# fit_transform() 学习词汇表和IDF,然后返回TF-IDF矩阵
tfidf_matrix = tfidf_vectorizer.fit_transform(corpus)
# 输出为稀疏矩阵(对高维度数据高效)
print("\nTF-IDF矩阵的形状:", tfidf_matrix.shape)
# 输出:TF-IDF矩阵的形状:(4, 15)
# 这表示在默认处理后,词汇表中包含4个文档和15个独立词语(特征)。
fit_transform方法首先学习词汇表 (vocabulary)(所有符合条件的独立词元 (token)),并计算整个语料库中每个词语的逆文档频率(IDF)。然后,它将语料库转换为文档-词语矩阵,其中每个单元格包含特定词语在特定文档中的TF-IDF分数。
生成的tfidf_matrix通常是SciPy稀疏矩阵。这种方式内存高效,因为文档-词语矩阵中的大多数条目都是零(大多数词语不会出现在大多数文档中)。
为了更好地理解这个矩阵,我们来看看学习到的词汇表以及(对于小型示例而言)矩阵的稠密表示。
# 获取词汇表(词语到列索引的映射)
feature_names = tfidf_vectorizer.get_feature_names_out()
print("\n词汇表(特征名称):")
print(feature_names)
# Output: ['away' 'brown' 'cat' 'dog' 'fox' 'in' 'jumps' 'lazy' 'never' 'over' 'quick' 'quickly' 'ran' 'slept' 'sun' 'the']
# 注意:如果启用默认词元模式或停用词,'is'、'a'等词可能会被移除。
# 为了本示例的清晰度,我们不使用隐式停用词移除功能重新运行:
# tfidf_vectorizer = TfidfVectorizer(stop_words=None)
# tfidf_matrix = tfidf_vectorizer.fit_transform(corpus)
# feature_names = tfidf_vectorizer.get_feature_names_out()
# 此输出假设使用默认分词且向量器初始化时未显式移除停用词
# 将稀疏矩阵转换为稠密NumPy数组以便检查
dense_tfidf_matrix = tfidf_matrix.toarray()
# 以DataFrame形式显示,提高可读性
df_tfidf = pd.DataFrame(dense_tfidf_matrix, columns=feature_names, index=[f"Doc_{i+1}" for i in range(len(corpus))])
print("\nTF-IDF矩阵(稠密):")
print(df_tfidf.round(2)) # 为显示目的四舍五入
您会注意到,许多文档中常见的词语(如“the”)其IDF值倾向于较低,这可能导致其TF-IDF分数低于更稀有、更具区分度的词语(如“fox”或“cat”),即使它们在文档中的词频(TF)相似。例如,“lazy”和“dog”出现在三个文档中,而“fox”仅出现在一个文档中。它们的TF-IDF分数将反映出文档频率的这种差异。
我们来可视化几个选定词语在这些文档中的TF-IDF分数。
# 选择几个词语进行可视化
terms_to_plot = ['dog', 'fox', 'lazy', 'quick', 'the']
term_indices = [list(feature_names).index(term) for term in terms_to_plot if term in feature_names]
term_labels = [feature_names[i] for i in term_indices]
# 提取这些词语的分数
scores_to_plot = dense_tfidf_matrix[:, term_indices]
# 为Plotly柱状图创建数据
plot_data = []
colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd'] # Plotly默认颜色
for i, term in enumerate(term_labels):
plot_data.append({
"x": [f"Doc_{j+1}" for j in range(len(corpus))],
"y": scores_to_plot[:, i],
"name": term,
"type": "bar",
"marker": {"color": colors[i % len(colors)]}
})
词语“dog”、“fox”、“lazy”、“quick”和“the”在四个样本文档中的TF-IDF分数。注意“the”尽管出现频繁,但得分相对较低,而“fox”仅在出现它的文档1中得分较高。“dog”和“lazy”因常共同出现而具有相似模式。
标准TF-IDF(使用一元词,即单个词语)会丢失词语顺序信息。“quick brown fox”和“fox brown quick”将具有相同的表示。N-gram通过将词语序列作为特征来帮助捕捉局部语境。
我们可以使用ngram_range参数 (parameter)配置TfidfVectorizer以包含N-gram。它接受一个元组(min_n, max_n)。例如,ngram_range=(1, 2)会生成一元词和二元词。
# 初始化向量器以包含一元词和二元词
ngram_vectorizer = TfidfVectorizer(ngram_range=(1, 2)) # 生成1-gram和2-gram
# 拟合和转换
ngram_tfidf_matrix = ngram_vectorizer.fit_transform(corpus)
# 检查新形状和部分特征名称
print("\n带N-gram (1, 2) 的TF-IDF矩阵形状:", ngram_tfidf_matrix.shape)
# 输出:带N-gram (1, 2) 的TF-IDF矩阵形状:(4, 31) -> 现在特征更多了!
ngram_feature_names = ngram_vectorizer.get_feature_names_out()
print("\nN-gram特征示例:")
# 为说明目的,打印前10个和后10个特征
print(list(ngram_feature_names[:10]) + list(ngram_feature_names[-10:]))
# 输出包含“brown fox”、“lazy dog”、“quick brown”、“the lazy”等特征。
您可以看到,加入N-gram后特征数量显著增加。这能捕捉更多语境(例如,区分“lazy dog”与“lazy”和“dog”分别出现的情况),但同时也增加了特征空间的维度。这可能使计算更耗时,并且有时需要更多数据以避免过拟合 (overfitting)。
通常的做法是使用一元词和二元词(ngram_range=(1, 2)),偶尔也使用三元词(ngram_range=(1, 3)),这取决于具体的任务和语料库大小。您可以使用TfidfVectorizer中的max_features参数来限制特征的总数,该参数会只保留按整个语料库词频排序的靠前特征。
# 示例:使用二元词同时限制特征数量
limited_ngram_vectorizer = TfidfVectorizer(ngram_range=(1, 2), max_features=20)
limited_ngram_matrix = limited_ngram_vectorizer.fit_transform(corpus)
print("\n带N-gram (1, 2) 且 max_features=20 的形状:", limited_ngram_matrix.shape)
# 输出:带N-gram (1, 2) 且 max_features=20 的形状:(4, 20)
limited_features = limited_ngram_vectorizer.get_feature_names_out()
print("\n受限特征集示例:")
print(limited_features[:10]) # 显示一些选定的靠前特征
在本实践部分,您学会了如何:
scikit-learn的TfidfVectorizer将原始文本文档转换为数值型TF-IDF矩阵。ngram_range参数 (parameter)捕捉局部词语顺序。max_features限制特征数量。生成有意义的数值特征,例如可借由N-gram改进的TF-IDF向量,是为机器学习 (machine learning)模型准备文本数据的一个基础步骤,我们将在下一章讨论这方面内容。
这部分内容有帮助吗?
© 2026 ApX Machine LearningAI伦理与透明度•