如何使用 ColumnTransformer() 返回数据框?

Blu*_*ail 8 encoder dataframe python-3.x scikit-learn

我有一个像这样的数据框:

department      review  projects salary satisfaction bonus  avg_hrs_month   left
0   operations  0.577569    3   low         0.626759    0   180.866070      0
1   operations  0.751900    3   medium      0.443679    0   182.708149      0
2   support     0.722548    3   medium      0.446823    0   184.416084      0
3   logistics   0.675158    4   high        0.440139    0   188.707545      0
4   sales       0.676203    3   high        0.577607    1   179.821083      0

Run Code Online (Sandbox Code Playgroud)

我想尝试 ColumnTransformer() 并返回转换后的数据帧。

ord_features = ["salary"]
ordinal_transformer = OrdinalEncoder()


cat_features = ["department"]
categorical_transformer = OneHotEncoder(handle_unknown="ignore")

ct = ColumnTransformer(
    transformers=[
        ("ord", ordinal_transformer, ord_features),
        ("cat", categorical_transformer, cat_features ),
           ]
)

df_new = ct.fit_transform(df)
df_new
Run Code Online (Sandbox Code Playgroud)

这给了我一个“类型为 '<class 'numpy.float64'>' 的稀疏矩阵”

如果我使用 pd.DataFrame(ct.fit_transform(df)) 那么我会得到一列:

                            0
0   (0, 0)\t1.0\n (0, 7)\t1.0
1   (0, 0)\t2.0\n (0, 7)\t1.0
2   (0, 0)\t2.0\n (0, 10)\t1.0
3   (0, 5)\t1.0
4   (0, 9)\t1.0

Run Code Online (Sandbox Code Playgroud)

但是,我期望看到像这样转换后的数据框?

    review  projects salary satisfaction bonus  avg_hrs_month   operations support ...
0   0.577569    3    1      0.626759     0      180.866070      1           0
1   0.751900    3    2      0.443679     0      182.708149      1           0  
2   0.722548    3    2      0.446823     0      184.416084      0           1
3   0.675158    4    3      0.440139     0      188.707545      0           0
4   0.676203    3    3      0.577607     1      179.821083      0           0
Run Code Online (Sandbox Code Playgroud)

可以用ColumnTransformer()吗?

ami*_*ola 20

正如评论中快速概述的那样,您的示例需要考虑以下几点:

  • 方法.fit_transform()通常返回稀疏矩阵numpy 数组。返回稀疏矩阵有节省内存的目的;考虑一下您对具有多个类别的分类属性进行单热编码的示例。您最终将得到一个包含许多列和每行一个非零条目的矩阵;使用稀疏矩阵,您可以仅存储非零元素的位置。在这些情况下,您可以调用.toarray()的输出.fit_transform()来获取 numpy 数组并将其传递给pd.DataFrame构造函数。

    实际上,在与您提供的类似的五行数据集上

    df = pd.DataFrame({
        'department': ['operations', 'operations', 'support', 'logistics', 'sales'],
        'review': [0.577569, 0.751900, 0.722548, 0.675158, 0.676203],
        'projects': [3, 3, 3, 4, 3],
        'salary': ['low', 'medium', 'medium', 'low', 'high'],
        'satisfaction': [0.626759, 0.751900, 0.722548, 0.675158, 0.676203],
        'bonus': [0, 0, 0, 0, 1],
        'avg_hrs_month': [180.866070, 182.708149, 184.416084, 188.707545, 179.821083],
        'left': [0, 0, 1, 0, 0]
    })
    
    ord_features = ["salary"]
    ordinal_transformer = OrdinalEncoder()
    
    cat_features = ["department"]
    categorical_transformer = OneHotEncoder(handle_unknown="ignore")
    
    ct = ColumnTransformer(transformers=[
        ("ord", ordinal_transformer, ord_features),
        ("cat", categorical_transformer, cat_features),
    ])
    
    Run Code Online (Sandbox Code Playgroud)

    我无法重现您的问题(即,我直接获得一个 numpy 数组),但基本上pd.DataFrame(ct.fit_transform(df).toarray())应该适合您的情况。这是您将得到的输出: 在此输入图像描述

  • 正如您所看到的,对于您的预期输出,这仅包含作为第一列的转换后(按顺序编码)的薪水列和从第二列到最后一列的转换后(单热编码)部门列。这是因为,正如您在docs中看到的,参数默认remainder设置为'drop',这意味着所有不受转换影响的列都将被删除。为了避免这种情况,您应该将其设置为'passthrough';这将帮助您转换所需的列并保持其他列不变。

    ct = ColumnTransformer(transformers=[
        ("ord", ordinal_transformer, ord_features),
        ("cat", categorical_transformer, cat_features )],
        remainder='passthrough'
    )
    
    Run Code Online (Sandbox Code Playgroud)

    pd.DataFrame(ct.fit_transform(df).toarray())在这种情况下,这将是您的输出:

    在此输入图像描述

  • 同样,正如您所看到的,列顺序也不是您在转换后所期望的顺序。长话短说,那是因为在ColumnTransformer

转换后的特征矩阵中的列顺序遵循转换器列表中指定列的顺序。除非在 passthrough 关键字中指定,否则原始特征矩阵中未指定的列将从生成的转换特征矩阵中删除。使用 passthrough 指定的那些列将添加到变压器输出的右侧。

我建议在本提案中应用 sklearn.compose.ColumnTransformer 后阅读保留列顺序

更新 10/2022 - sklearn 版本 1.2.dev0

使用sklearn版本1.2.0可以ColumnTransformer更轻松地解决转换实例时返回 DataFrame 的问题。该版本尚未发布,但您可以1.2.dev0通过安装夜间构建来在 dev (版本)中测试以下内容:

pip install --pre --extra-index https://pypi.anaconda.org/scipy-wheels-nightly/simple scikit-learn -U
Run Code Online (Sandbox Code Playgroud)

ColumnTransformer以及其他转换器)现在公开了一种.set_output()方法,该方法可以通过向其传递参数来配置转换器以输出 pandas DataFrame transform='pandas'

因此,示例变为:

import pandas as pd
from sklearn.preprocessing import LabelEncoder, OneHotEncoder, OrdinalEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import RandomForestClassifier

df = pd.DataFrame({
    'department': ['operations', 'operations', 'support', 'logistics', 'sales'],
    'review': [0.577569, 0.751900, 0.722548, 0.675158, 0.676203],
    'projects': [3, 3, 3, 4, 3],
    'salary': ['low', 'medium', 'medium', 'low', 'high'],
    'satisfaction': [0.626759, 0.751900, 0.722548, 0.675158, 0.676203],
    'bonus': [0, 0, 0, 0, 1],
    'avg_hrs_month': [180.866070, 182.708149, 184.416084, 188.707545, 179.821083],
    'left': [0, 0, 1, 0, 0]
})

ord_features = ["salary"]
ordinal_transformer = OrdinalEncoder()

cat_features = ["department"]
categorical_transformer = OneHotEncoder(sparse_output=False, handle_unknown="ignore")

ct = ColumnTransformer(transformers=[
    ("ord", ordinal_transformer, ord_features),
    ("cat", categorical_transformer, cat_features )],
    remainder='passthrough'
)

ct.set_output('pandas')
df_pandas = ct.fit_transform(df)
df_pandas
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

输出也变得更容易阅读,因为它具有正确的列名称(事实上,在每个步骤中,其组成的转换器ColumnTransformer确实具有属性feature_names_in_;因此在转换输入时您不会再丢失列名称)。

最后一点。请注意,该示例现在需要将参数sparse_output=False传递给OneHotEncoder实例才能工作。


Dat*_*tor 6

这个答案跳过了解决方法,直接提供了 scikit-learn 1.2+ 版本的解决方案

从 sklearn 1.2 版本开始,变压器可以pandas DataFrame直接返回 a ,无需进一步处理。它是通过 完成的set_output,可以通过调用set_output方法或通过设置全局配置每个估计器set_config(transform_output="pandas")。请参阅scikit-learn 1.2 的发布亮点 - 使用 set_output API 进行 Pandas 输出

在你的情况下,解决方案是:

ord_features = ["salary"]
ordinal_transformer = OrdinalEncoder()


cat_features = ["department"]
categorical_transformer = OneHotEncoder(handle_unknown="ignore")

ct = ColumnTransformer(
    transformers=[
        ("ord", ordinal_transformer, ord_features),
        ("cat", categorical_transformer, cat_features ),
           ]
)

# Add the following line to your code
ct.set_output(transform="pandas")

df_new = ct.fit_transform(df)
df_new
Run Code Online (Sandbox Code Playgroud)