简介
在本实验中,我们将学习如何在包含不同类型特征的数据集上使用 Scikit-Learn 的 ColumnTransformer。当数据集包含需要不同特征提取和处理管道的组件时,此技术非常有用。
虚拟机提示
虚拟机启动完成后,点击左上角切换到“笔记本”标签,以访问 Jupyter Notebook 进行练习。
有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。
如果你在学习过程中遇到问题,请随时向 Labby 提问。课程结束后提供反馈,我们将立即为你解决问题。
数据集
我们将使用 20 个新闻组数据集,该数据集由 20 个主题的新闻组帖子组成。根据特定日期之前和之后发布的消息,数据集被分为训练集和测试子集。为了加快运行速度,我们将只使用来自 2 个类别的帖子。
categories = ["sci.med", "sci.space"]
X_train, y_train = fetch_20newsgroups(
random_state=1,
subset="train",
categories=categories,
remove=("footers", "quotes"),
return_X_y=True,
)
X_test, y_test = fetch_20newsgroups(
random_state=1,
subset="test",
categories=categories,
remove=("footers", "quotes"),
return_X_y=True,
)
创建转换器
我们将创建从数据集中提取特征的转换器。我们将定义两个执行数据转换的函数,然后使用 Scikit-Learn 的 FunctionTransformer 创建转换器。
def subject_body_extractor(posts):
## 构造一个具有两列的对象数据类型数组
## 第一列 ='subject',第二列 = 'body'
features = np.empty(shape=(len(posts), 2), dtype=object)
for i, text in enumerate(posts):
## 临时变量 `_` 存储 '\n\n'
headers, _, body = text.partition("\n\n")
## 将正文文本存储在第二列
features[i, 1] = body
prefix = "Subject:"
sub = ""
## 将 'Subject:' 之后的文本保存在第一列
for line in headers.split("\n"):
if line.startswith(prefix):
sub = line[len(prefix) :]
break
features[i, 0] = sub
return features
subject_body_transformer = FunctionTransformer(subject_body_extractor)
def text_stats(posts):
return [{"length": len(text), "num_sentences": text.count(".")} for text in posts]
text_stats_transformer = FunctionTransformer(text_stats)
分类管道
我们将创建一个管道,该管道从数据集中提取特征,将它们组合起来,并在组合后的特征集上训练一个分类器。我们将使用 Scikit-Learn 的 Pipeline 和 ColumnTransformer 来实现这一点。
pipeline = Pipeline(
[
## 提取主题和正文
("subjectbody", subject_body_transformer),
## 使用 ColumnTransformer 组合主题和正文特征
(
"union",
ColumnTransformer(
[
## 主题(第 0 列)的词袋模型
("subject", TfidfVectorizer(min_df=50), 0),
## 正文(第 1 列)的带分解的词袋模型
(
"body_bow",
Pipeline(
[
("tfidf", TfidfVectorizer()),
("best", TruncatedSVD(n_components=50)),
]
),
1,
),
## 从帖子正文中提取文本统计信息的管道
(
"body_stats",
Pipeline(
[
(
"stats",
text_stats_transformer,
), ## 返回一个字典列表
(
"vect",
DictVectorizer(),
), ## 字典列表 -> 特征矩阵
]
),
1,
),
],
## 上述 ColumnTransformer 特征的权重
transformer_weights={
"subject": 0.8,
"body_bow": 0.5,
"body_stats": 1.0,
},
),
),
## 在组合特征上使用 SVC 分类器
("svc", LinearSVC(dual=False)),
],
verbose=True,
)
训练与测试
我们将在训练数据上拟合我们的管道,并使用它来预测 X_test 的主题。然后打印我们管道的性能指标。
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print("Classification report:\n\n{}".format(classification_report(y_test, y_pred)))
总结
在本实验中,我们学习了如何在包含不同类型特征的数据集上使用 Scikit-Learn 的 ColumnTransformer。我们创建了从数据集中提取特征的转换器,并使用它们在组合后的特征集上训练分类器。ColumnTransformer 使我们能够在单个管道中处理不同类型的特征。