具有异构数据源的列变形器¶
数据集通常可以包含需要不同特征提取和处理管道的组件。 在以下情况下可能会发生这种情况:
您的数据集包含异构数据类型(例如,光栅图像和文字标题),
您的数据集存储在pandas.DataFrame中,不同的列需要不同的处理管道。
本示例演示如何在包含不同类型要素的数据集上使用ColumnTransformer。 功能的选择并不是特别有帮助,但是可以用来说明该技术。
# Author: Matt Terry <matt.terry@gmail.com>
#
# License: BSD 3 clause
import numpy as np
from sklearn.preprocessing import FunctionTransformer
from sklearn.datasets import fetch_20newsgroups
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_extraction import DictVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import classification_report
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.svm import LinearSVC
20个新闻组数据集
我们将使用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)
print(X_train[0])
每个功能都包含有关该帖子的元信息,例如主题和新闻帖子的主体。
输出:
Subject: Re: Metric vs English
Article-I.D.: mksol.1993Apr6.131900.8407
Organization: Texas Instruments Inc
Lines: 31
American, perhaps, but nothing military about it. I learned (mostly)
slugs when we talked English units in high school physics and while
the teacher was an ex-Navy fighter jock the book certainly wasn't
produced by the military.
[Poundals were just too flinking small and made the math come out
funny; sort of the same reason proponents of SI give for using that.]
--
"Insisting on perfect safety is for people who don't have the balls to live in the real world." -- Mary Shafer, NASA Ames Dryden
(译者注:这里输出的是英文稿件中的内容,若翻译成中文用户将感到非常困惑,故保留英文内容,不予翻译。)
创建转换器
首先,我们需要一个转换器来提取每个帖子的主题和正文。 由于这是无状态转换(不需要训练数据中的状态信息),因此我们可以定义一个执行数据转换的函数,然后使用FunctionTransformer创建scikit-learn转换器。
def subject_body_extractor(posts):
#用两列构造对象dtype数组
#第一列=“主题”,第二列=“主体”
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 = ''
# 在第一栏中的“主题:”之后保存文本
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),
# 使用ColumnTransformer组合标题和主体特征
('union', ColumnTransformer(
[
# 标题词袋(col 0)
('subject', TfidfVectorizer(min_df=50), 0),
# 文章主体分解的词袋(col 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))
)
输出:
[Pipeline] ....... (step 1 of 3) Processing subjectbody, total= 0.0s
[Pipeline] ............. (step 2 of 3) Processing union, total= 0.6s
[Pipeline] ............... (step 3 of 3) Processing svc, total= 0.0s
Classification report:
precision recall f1-score support
0 0.84 0.88 0.86 396
1 0.87 0.83 0.85 394
accuracy 0.85 790
macro avg 0.85 0.85 0.85 790
weighted avg 0.85 0.85 0.85 790
脚本的总运行时间:(0分钟3.380秒)