如何使用 sklearn 列转换器?

Posted

技术标签:

【中文标题】如何使用 sklearn 列转换器?【英文标题】:How to use sklearn Column Transformer? 【发布时间】:2019-06-07 04:38:15 【问题描述】:

我正在尝试使用 LabelEncoder 然后使用 OneHotEncoder 将分类值(在我的情况下是国家列)转换为编码值,并且能够转换分类值。但是我收到了警告,例如 OneHotEncoder 'categorical_features' 关键字已弃用“请改用 ColumnTransformer”。那么如何使用 ColumnTransformer 来达到相同的效果呢?

以下是我的输入数据集和我尝试过的代码

Input Data set

Country Age Salary
France  44  72000
Spain   27  48000
Germany 30  54000
Spain   38  61000
Germany 40  67000
France  35  58000
Spain   26  52000
France  48  79000
Germany 50  83000
France  37  67000


import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder, OneHotEncoder

#X is my dataset variable name

label_encoder = LabelEncoder()
x.iloc[:,0] = label_encoder.fit_transform(x.iloc[:,0]) #LabelEncoder is used to encode the country value
hot_encoder = OneHotEncoder(categorical_features = [0])
x = hot_encoder.fit_transform(x).toarray()

我得到的输出是,如何使用列转换器获得相同的输出

0(fran) 1(ger) 2(spain) 3(age)  4(salary)
1         0       0      44        72000
0         0       1      27        48000
0         1       0      30        54000
0         0       1      38        61000
0         1       0      40        67000
1         0       0      35        58000
0         0       1      36        52000
1         0       0      48        79000
0         1       0      50        83000
1         0       0      37        67000

我尝试了以下代码

from sklearn.compose import ColumnTransformer, make_column_transformer

preprocess = make_column_transformer(

    ( [0], OneHotEncoder())
)
x = preprocess.fit_transform(x).toarray()

我能够使用上述代码对国家/地区列进行编码,但转换后 x 变量中缺少年龄和薪水列

【问题讨论】:

transformer = ColumnTransformer( transformers=[ ("Country", # Just a name OneHotEncoder(), # The transformer class [0] # The column(s) to be applied. ) ], rest ='passthrough' ) X = transformer.fit_transform(X) 您的代码/方法中的一些问题/建议: 1. 您不需要标签编码器(理想情况下,它用于响应变量)。参考:***.com/a/63822728/5114585 2. 可以直接使用 One Hot Encoder [待续..] 3.对于这些数据,您也可以直接选择分类列,但要自动对所有分类列应用 OHE,您可以使用 ColumnTransformer() 或 make_column_transfer [它们略有不同。 ColumnTransformer需要步骤的命名,make_column_transformer不需要] 4. 为column Transformer选择分类变量可以通过使用列名、索引、数据类型等多种方式完成[参考sklearn文档了解更多] 【参考方案1】:

将连续数据编码为 Salary 有点奇怪。除非您将薪水划分为某些范围/类别,否则这是没有意义的。如果我是你,我会这样做:

import pandas as pd
import numpy as np

from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder



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

categorical_features = ['Age','Country']
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(solver='lbfgs'))])  
                  

这样使用它:

clf.fit(X_train,y_train)

这将应用预处理器,然后将转换后的数据传递给预测器。

更新:

如果我们想动态选择数据类型,我们可以修改我们的预处理器以使用数据类型的列选择器:

from sklearn.compose import make_column_selector as selector

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

使用网格搜索

param_grid = 
    'preprocessor__num__imputer__strategy': ['mean', 'median'],
    'classifier__C': [0.1, 1.0, 10, 100],
    'classifier__solver': ['lbfgs', 'sag'],


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

获取特征名称


preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, selector(dtype_include="numeric")),
        ('cat', categorical_transformer, selector(dtype_include="category"))],
    verbose_feature_names_out=False, # added this line
)

# now we can access feature names with

clf[:-1]. get_feature_names_out() # step before estimator

【讨论】:

如何将 pipeline 与“GridSearchCV”结合起来,还能打印出最好的分数和最好的参数? sklearn如何知道哪一列是数字的,哪一列是分类的。 我们自己传递了numeric_features = ['Salary'] 等。我们也可以使用from sklearn.compose import make_column_selector 并仅选择数值参见scikit-learn.org/stable/auto_examples/compose/… 嗨@PraysonW.Daniel,我发现你对这个问题的回答对我目前的问题非常有用。如果你不介意的话,我可以请你看看吗? ***.com/questions/67493509/…(也许你可以帮我弄清楚我做错了什么)。非常感谢【参考方案2】:

我认为海报并没有试图改变年龄和薪水。从文档(https://scikit-learn.org/stable/modules/generated/sklearn.compose.make_column_transformer.html)中,您 ColumnTransformer(和 make_column_transformer)仅在转换器中指定的列(即,您的示例中的 [0])。您应该设置剩余=“passthrough”以获取其余列。换句话说:

preprocessor = make_column_transformer( (OneHotEncoder(),[0]),remainder="passthrough")
x = preprocessor.fit_transform(x)

【讨论】:

你如何处理这个警告? FutureWarning:整数数据的处理将在 0.22 版中更改。目前,类别是根据范围 [0, max(values)] 确定的,而将来它们将根据唯一值确定。如果您想要未来的行为并消除此警告,您可以指定“categories='auto'”。如果您在此 OneHotEncoder 之前使用 LabelEncoder 将类别转换为整数,那么您现在可以直接使用 OneHotEncoder。 warnings.warn(msg, FutureWarning) bro @FawwazYusran ... 注释掉包含 labelEncoder.... 的行直接用路人的建议【参考方案3】:

@Fawwaz Yusran 解决这个警告...

FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values. If you want the future behaviour and silence this warning, you can specify "categories='auto'". In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly. warnings.warn(msg, FutureWarning)

删除以下...

labelencoder_X = LabelEncoder()
X[:, 0] = labelencoder_X.fit_transform(X[:, 0])

由于您直接使用 OneHotEncoder,因此不需要 LabelEncoder。

【讨论】:

labelencoder 仅用于标签,y/target 不是 X/features ;)【参考方案4】:
from sklearn.compose import make_column_transformer
preprocess = make_column_transformer(
    (OneHotEncoder(categories='auto'), [0]), 
    remainder="passthrough")
X = preprocess.fit_transform(X)

我使用上面的代码解决了同样的问题。

【讨论】:

【参考方案5】:

由于您只转换国家/地区列(即您的示例中的 [0])。使用remainder="passthrough" 获取剩余的列,以便您按原样获取这些列。

尝试:

from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer
labelencoder=LabelEncoder()
x[:,0]=labelencoder.fit_transform(x[:,0])
preprocess = ColumnTransformer(transformers=[('onehot', OneHotEncoder() 
                               [0])],remainder="passthrough")
x = np.array(preprocess.fit_transform(x), dtype=np.int)

【讨论】:

【参考方案6】:

最简单的方法是在你的 CVS 数据框上使用熊猫假人

dataset = pd.read_csv("yourfile.csv")
dataset = pd.get_dummies(dataset,columns=['Country'])

已完成您的数据集将如下所示

【讨论】:

我使用 sklearn 已经一年多了,但我并不知道这一点。非常感谢! 使用 pandas 进行数据预处理可能更容易,但使用 sklearn 具有相同的优势,因为预处理步骤可用于管道,稍后可用于交叉验证模型性能 @Shiva_Adasule 我尝试了这个,但得到了与转换之前相同的错误。错误状态:ValueError:无法将字符串转换为浮点数:'Honda'【参考方案7】:

您可以直接使用OneHotEncoder,不需要使用LabelEncoder

#  Encoding categorical data
from sklearn.preprocessing import OneHotEncoder
transformer = ColumnTransformer(
    transformers=[
        ("OneHotEncoder",
         OneHotEncoder(),
         [0]              # country column or the column on which categorical operation to be performed
         )
    ],
    remainder='passthrough'
)
X = transformer.fit_transform(X.tolist())

【讨论】:

【参考方案8】:
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder_previsores = LabelEncoder()

onehotencorder = ColumnTransformer(transformers=[("OneHot", OneHotEncoder(), [0])],remainder='passthrough')
x= onehotencorder.fit_transform(x).toarray()

OneHotEnocoder 的一大优势是一次转换多列,参见传递多列的示例

onehotencorder = ColumnTransformer(transformers=[("OneHot", OneHotEncoder(), [1,3,5,6,7,8,9,13])],remainder='passthrough')

如果是单列,你可以用传统的方式来做

from sklearn.preprocessing import LabelEncoder
labelencoder_predictors = LabelEncoder()
x[:,0] = labelencoder_predictors.fit_transform(x[:,0])

另一个建议。

不要使用名称为 x、y、z 的变量 把它代表什么,例如: 预测器, 类, 国家,ecc。

【讨论】:

【参考方案9】:
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer
labelencoder_X = LabelEncoder()
X[:, 0] = labelencoder_X.fit_transform(X[:, 0])
print(X[:, 0])
ct = ColumnTransformer([("Country", OneHotEncoder(), [1])], remainder = 'passthrough')
#onehotencoder = OneHotEncoder(categorical_features = [0])
X = ct.fit_transform(X).toarray()

【讨论】:

以上是关于如何使用 sklearn 列转换器?的主要内容,如果未能解决你的问题,请参考以下文章

如何在具有多个数据帧列输入的 sklearn 管道中编写转换器

如何在 sklearn 中修复这个自定义转换器?

如何在使用 sklearn 进行一次热编码后给出列名?

如何在使用 sklearn 进行一次热编码后给出列名?

使用 sklearn OneHotEncoder 时如何去掉数字列?

mlflow 如何使用自定义转换器保存 sklearn 管道?