混合型列式转换器

本示例说明了如何使用sklearn.compose.ColumnTransformer将不同的预处理和特征提取管道应用于特征的不同子集。 这对于包含异构数据类型的数据集特别方便,因为我们可能要缩放数字特征并对分类特征进行独热编码。

在此示例中,数字数据在均值输入后进行标准缩放,而分类数据在使用新类别(“缺失”)插入缺失值后进行一次热编码。

此外,我们展示了两种不同的方式将列分配给特定的预处理器:按列名称和按列数据类型。

最后,使用sklearn.pipeline.Pipeline以及简单的分类模型将预处理管道集成到完整的预测管道中。

# 作者: Pedro Morales <part.morales@gmail.com>
#
# 执照: BSD 3 clause

import numpy as np

from sklearn.compose import ColumnTransformer
from sklearn.datasets import fetch_openml
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split, GridSearchCV

np.random.seed(0)

# 从网站https://www.openml.org/d/40945加载数据
X, y = fetch_openml("titanic", version=1, as_frame=True, return_X_y=True)

# 另外,X和y可以直接从frame属性获得:
# X = titanic.frame.drop('survived', axis=1)
# y = titanic.frame['survived']

通过按名称选择列来使用ColumnTransformer

我们将使用以下功能训练分类器:

数值特征:

  • 年龄:浮点数;

  • 票价:浮点数。

分类特征:

  • 出发:编码为字符串{'C','S','Q'}的类别;

  • 性别:编码为字符串{'female','male'}的类别;

  • pclass:有序整数{1、2、3}。

我们为数字和分类数据创建预处理管道。

numeric_features = ['age''fare']
numeric_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())])

categorical_features = ['embarked''sex''pclass']
categorical_transformer = Pipeline(steps=[
    ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
    ('onehot', OneHotEncoder(handle_unknown='ignore'))])

preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)])

# 将分类器追加到预处理管道。
# 现在我们有了完整的预测管道。

clf = Pipeline(steps=[('preprocessor', preprocessor),
                      ('classifier', LogisticRegression())])

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

clf.fit(X_train, y_train)
print("model score: %.3f" % clf.score(X_test, y_test))

输出:

model score: 0.790

Pipeline的HTML表示

在Jupyter notebook中打印管道时,估算器的HTML表示将显示如下:

from sklearn import set_config
set_config(display='diagram')
clf

通过按数据类型选择列来使用ColumnTransformer

在处理清理的数据集时,可以通过使用列的数据类型来决定是否将列视为数字或分类特征来自动进行预处理。 sklearn.compose.make_column_selector提供了这种可能性。 首先,为了简化示例,我们仅选择列的子集。

subset_feature = ['embarked''sex''pclass''age''fare']
X = X[subset_feature]

然后,我们内省有关每种列数据类型的信息。

X.info()

输出:

<class 'pandas.core.frame.DataFrame'>
RangeIndex:
 1309 entries, 0 to 1308
Data columns (total 5 columns):
 #   Column    Non-Null Count  Dtype
---  ------    --------------  -----
 0   embarked  1307 non-null   category
 1   sex       1309 non-null   category
 2   pclass    1309 non-null   float64
 3   age       1046 non-null   float64
 4   fare      1308 non-null   float64
dtypes: category(2), float64(3)
memory usage: 33.6 KB

我们可以观察到,在使用fetch_openml加载数据时,将embarked和sex列标记为category列。 因此,我们可以使用此信息将分类列分派给categorical_transformer,将其余列分派给numeric_transformer。

注意实际上,您将必须处理自己的列数据类型。 如果要将某些列视为类别,则必须将它们转换为类别列。 如果您使用的是熊猫,则可以参考其有关分类数据的文档。

from sklearn.compose import make_column_selector as selector

preprocessor = ColumnTransformer(transformers=[
    ('num', numeric_transformer, selector(dtype_exclude="category")),
    ('cat', categorical_transformer, selector(dtype_include="category"))
])

# 重现相同的匹配/得分过程
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

clf.fit(X_train, y_train)
print("model score: %.3f" % clf.score(X_test, y_test))

输出:

model score: 0.794

在网格搜索中使用预测管道

网格搜索还可以在ColumnTransformer对象中定义的不同预处理步骤以及作为管道的一部分的分类器的超参数中执行。 我们将使用sklearn.model_selection.GridSearchCV搜索数值预处理的不当策略和逻辑回归的正则化参数。

param_grid = {
    'preprocessor__num__imputer__strategy': ['mean''median'],
    'classifier__C': [0.11.010100],
}

grid_search = GridSearchCV(clf, param_grid, cv=10)
grid_search.fit(X_train, y_train)

print(("best logistic regression from grid search: %.3f"
       % grid_search.score(X_test, y_test)))

输出:

best logistic regression from grid search: 0.794

脚本的总运行时间:(0分钟3.461秒)