5

我在训练期间使用标签编码器,并希望通过保存并稍后加载它来在生产中使用相同的编码器。无论我在网上找到什么解决方案,都只允许标签编码器一次应用于单个列,如下所示:

for col in col_list:
    df[col]= df[[col]].apply(LabelEncoder().fit_transform)

在这种情况下,我如何保存它并在以后使用它?因为我尝试拟合整个数据帧,但出现以下错误。

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
C:\Users\DA~1\AppData\Local\Temp/ipykernel_3884/730613134.py in <module>
----> 1 l_enc.fit_transform(df_join[le_col].astype(str))

~\anaconda3\envs\ReturnRate\lib\site-packages\sklearn\preprocessing\_label.py in fit_transform(self, y)
    113             Encoded labels.
    114         """
--> 115         y = column_or_1d(y, warn=True)
    116         self.classes_, y = _unique(y, return_inverse=True)
    117         return y

~\anaconda3\envs\ReturnRate\lib\site-packages\sklearn\utils\validation.py in column_or_1d(y, warn)
   1022         return np.ravel(y)
   1023 
-> 1024     raise ValueError(
   1025         "y should be a 1d array, got an array of shape {} instead.".format(shape)
   1026     )

ValueError: y should be a 1d array, got an array of shape (3949037, 14) instead.

我想将标签编码器安装到具有 10 列(所有分类)的数据帧,保存并稍后在生产中加载。

4

3 回答 3

2

首先,我想指出labelEncoder用于编码目标变量。如果您在预测变量上应用 labelEncoder,则会使它们连续,例如 0、1、2、3 等,这可能没有意义。

对于分类预测器,您应该使用onehotencoding

如果您确定 labelencode,它是这样的:

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

df = pd.DataFrame({'f1':np.random.choice(['a','b','c'],100),
'f2':np.random.choice(['x','y','z'],100)})

col_list = ['f1','f2']

df[col_list].apply(LabelEncoder().fit_transform)

如果要保留编码器,可以将其存储在字典中:

le = {}
for col in col_list:
    le[col] = LabelEncoder().fit(df[col].values)

le['f1'].transform(df['f1'])

array([1, 0, 2, 0, 2, 0, 2, 1, 1, 2, 0, 1, 2, 1, 1, 1, 0, 2, 1, 2, 1, 2,
       2, 2, 0, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1,
       0, 1, 1, 1, 2, 2, 1, 0, 2, 1, 2, 2, 2, 1, 0, 0, 2, 2, 0, 1, 2, 2,
       0, 2, 1, 2, 1, 1, 1, 1, 1, 2, 2, 0, 2, 0, 1, 1, 1, 0, 2, 0, 0, 2,
       0, 1, 1, 2, 1, 0, 0, 2, 0, 1, 1, 2])

for col in col_list:
    df[col] = le[col].transform(df[col])

再次,我会更多地考虑使用 labelEncoding 是否正确。

于 2021-11-16T10:01:47.673 回答
2

正如@StupidWolf所说,LabelEncoder应该仅用于编码目标变量。

scikit-learn 提供了多种方法来为特征向量编码分类变量:

  • OneHotEncoder将类别编码为一个热门数值
  • OrdinalEncoder它将类别编码为数值。

OrdinalEncoder执行与特征值相同的操作LabelEncoder

您可以使用ColumnTransformer将不同的预处理包装到一个对象中,以后可以使用 pickle 轻松保存,如下例所示:

from sklearn.compose import make_column_transformer, make_column_selector
from sklearn.preprocessing import OrdinalEncoder
import pandas as pd
import numpy as np

df = pd.DataFrame(
    {
        "col_1": ["A", "B", "B", "D", "E", "F", "A", "B"],
        "col_2": ["X", "X", "X", "Y", "Y", "Z", "Z", "X"],
        "col_3": [42] * 8,
    }
)
cols = ["col_1", "col_2"]

pre_processeing = make_column_transformer(
    (OrdinalEncoder(handle_unknown="use_encoded_value", unknown_value=np.nan), cols)
)


df.loc[:, cols] = pre_processeing.fit_transform(df[cols])

哪个输出:

   col_1  col_2  col_3
0    0.0    0.0     42
1    1.0    0.0     42
2    1.0    0.0     42
3    2.0    1.0     42
4    3.0    1.0     42
5    4.0    2.0     42
6    0.0    2.0     42
7    1.0    0.0     42

安装好预处理后,可以使用以下方式轻松存储和加载它pickle

import pickle

#Dump preprocessing
pickle.dump(pre_processeing, open("pre_processing.p", "wb"))

#Load preprocessing
pre_processeing = pickle.load(open("pre_processing.p", "rb"))

总而言之,我主张这样ColumnTransformer做有以下好处:

  • 可以轻松添加针对不同列的额外预处理(例如StandardScaler,对于数值)
  • 此预处理可以包含在 aPipeline中以具有执行预测的端到端模型
  • 这是一个可以轻松序列化的单个对象pickle
于 2021-12-03T08:29:28.860 回答
0

TL;DR使用SklearnTransformerWrapper特征引擎库

from feature_engine.wrappers import SklearnTransformerWrapper

multi_col_transformer = SklearnTransformerWrapper(
    transformer=# your sklearn- transformer,
    variables=# variables to apply transformation to
)

如果您正在寻找一种具有不同库特征引擎的方法,分类编码器接受一个variables参数以将计算应用于多个列。另一种方法是SklearnTransformerWrapper将任何 Scikit-learn 转换器应用于一组变量。

from feature_engine.wrappers import SklearnTransformerWrapper
from sklearn.preprocessing import OrdinalEncoder

import pandas as pd
import joblib

transformer_name = 'multi_col_encoder.joblib'
cols_list = [
    'country',
    'category'
]

d_train = {
    'country': ['AR', 'AR', 'MEX', 'BR', 'MEX'],
    'category': ['Small', 'High', 'High', 'Medium', 'Small']
}

d_unknown = {
    'country': ['BR', 'AR', 'MEX'],
    'category': ['High', 'Medium', 'Small']
}

df_train = pd.DataFrame(d_train)
df_unknown = pd.DataFrame(d_unknown)

# Apply a sklearn enconder to multiple columns with SklearnTransformerWrapper
multi_col_oe = SklearnTransformerWrapper(
    transformer=OrdinalEncoder(
        handle_unknown='use_encoded_value', unknown_value=-1
    ),
    variables=cols_list
)

df_train = multi_col_oe.fit_transform(df_train)

df_train
>>>
country category
0   0.0 2.0
1   0.0 0.0
2   2.0 0.0
3   1.0 1.0
4   2.0 2.0

# Dump transformer to use later
joblib.dump(multi_col_oe, transformer_name)

# Load transformer with learned encoder logic
transformer_for_prod = joblib.load(transformer_name)

# Apply transformer to unknown data
transformer_for_prod.transform(df_unknown)
>>>
country category
0   1.0 0.0
1   0.0 1.0
2   2.0 2.0

正如@StupidWolf 所说,如果您在分类变量中假设顺序,则应该使用OrdinalEncoder而不是LabelEncoder. 尽管它们执行类似的计算,但OrdinalEncoder允许您处理以后可能遇到的未知值。

最后,特征引擎分类编码器还提供了编码分类变量的其他可能性。

于 2021-12-06T15:07:20.220 回答