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 后阅读保留列顺序。
columns要传递给pd.DataFrame构造函数的参数。事实上,OrdinalEncoder(与 不同OneHotEncoder)没有提供一种.get_feature_names_out()可以轻松传递columns=ct.get_feature_names_out()给pd.DataFrame构造函数的方法。请参阅带有 OHE 的 ColumnTransformer 和 Pipeline - 执行 ct 后 OHE 编码字段是保留还是删除?其用法示例。使用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实例才能工作。
从 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)