在机器学习项目中,经常会遇到需要对不同类型的数据应用不同的特征提取和处理方法的情况。例如,数据集中可能包含不同类型的数据(如栅格图像和文本标题),或者数据存储在pandas.DataFrame中,不同的列需要不同的处理流程。本文将展示如何使用ColumnTransformer来处理包含不同类型特征的数据集。虽然所选特征并不特别有用,但足以说明这种技术。
将使用20 newsgroups数据集,该数据集包含了来自20个主题的新闻组帖子。这个数据集根据特定日期前后发布的帖子被分为训练和测试子集。为了加快运行时间,只使用两个类别的帖子。
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)
每个特征包括关于该帖子的元信息,如主题和新闻帖子的正文。
print(X_train[0])
输出示例:
From: mccall@mksol.dseg.ti.com (fred j mccall 575-3539) Subject: Re: Metric vs English Article-I.D.: mksol.1993Apr6.131900.8407 Organization: Texas Instruments Inc Lines: 31
首先,希望一个转换器能够提取每个帖子的主题和正文。由于这是一个无状态转换(不需要训练数据的状态信息),可以定义一个执行数据转换的函数,然后使用FunctionTransformer创建一个scikit-learn转换器。
def subject_body_extractor(posts):
features = np.empty(shape=(len(posts), 2), dtype=object)
for i, text in enumerate(posts):
headers, _, body = text.partition("\n\n")
features[i, 1] = body
prefix = "Subject:"
sub = ""
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)
下面的处理流程使用SubjectBodyExtractor从每个帖子中提取主题和正文,生成一个(n_samples, 2)数组。然后使用ColumnTransformer计算主题和正文的标准词袋特征,以及正文的文本长度和句子数量,并将它们组合起来,然后训练一个分类器来处理组合的特征集。
pipeline = Pipeline([
("subjectbody", subject_body_transformer),
("union", ColumnTransformer([
("subject", TfidfVectorizer(min_df=50), 0),
("body_bow", Pipeline([
("tfidf", TfidfVectorizer()),
("best", PCA(n_components=50, svd_solver="arpack")),
]), 1),
("body_stats", Pipeline([
("stats", text_stats_transformer),
("vect", DictVectorizer()),
]), 1),
], transformer_weights={"subject": 0.8, "body_bow": 0.5, "body_stats": 1.0})),
("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)))
分类报告示例:
Classification report: precision recall f1-score support 0 0.84 0.87 0.86 396 1 0.87 0.84 0.85 394 accuracy 0.86 790 macro avg 0.86 0.86 0.86 790 weighted avg 0.86 0.86 0.86 790