scikit-learn中跨多列的标签编码

我试图使用scikit-learn的LabelEncoder来编码字符串标签的熊猫DataFrame。由于数据帧有很多(50+)列,我想避免为每一列创建LabelEncoder对象;我宁愿只有一个大的LabelEncoder对象,它在所有我的数据列中工作。

将整个DataFrame扔到LabelEncoder中会产生以下错误。请记住,我在这里使用的是虚拟数据;实际上,我正在处理大约50列的字符串标记数据,所以需要一个解决方案,不引用任何列的名称。

import pandas
from sklearn import preprocessing


df = pandas.DataFrame({
'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'],
'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
'New_York']
})


le = preprocessing.LabelEncoder()


le.fit(df)

Traceback(最近一次调用): 文件“”,第1行,在 文件"/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/预处理/label.py",第103行 y = column_or_1d(y, warn=True) 文件"/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py",第306行,在column_or_1d中 raise ValueError("错误的输入形状{0}".format(形状)) ValueError:错误的输入形状(6,3)

对于如何解决这个问题有什么想法吗?

338593 次浏览

不,LabelEncoder不这样做。它接受类标签的1维数组并生成1维数组。它的设计目的是处理分类问题中的类标签,而不是任意数据,任何强迫它用于其他用途的尝试都需要代码将实际问题转换为它解决的问题(并将解决方案转换回原始空间)。

假设你只是想获得一个sklearn.preprocessing.LabelEncoder()对象,它可以用来表示你的列,你所要做的就是:

le.fit(df.columns)
在上面的代码中,每一列都有一个唯一的数字。 更准确地说,你将得到df.columnsle.transform(df.columns.get_values())的1:1映射。要获得列的编码,只需将其传递给le.transform(...)。例如,下面将获得每列的编码:

le.transform(df.columns.get_values())

假设你想为你所有的行标签创建一个sklearn.preprocessing.LabelEncoder()对象,你可以这样做:

le.fit([y for x in df.get_values() for y in x])

在本例中,您很可能拥有非唯一的行标签(如您的问题所示)。要查看编码器创建了哪些类,可以执行le.classes_。你会注意到它应该有与set(y for x in df.get_values() for y in x)中相同的元素。再次使用le.transform(...)将行标签转换为编码标签。作为一个例子,如果你想检索df.columns数组的第一列和第一行的标签,你可以这样做:

le.transform([df.get_value(0, df.columns[0])])

你在评论中提出的问题有点复杂,但仍然可以 完成:< / p >

le.fit([str(z) for z in set((x[0], y) for x in df.iteritems() for y in x[1])])

上面的代码实现了以下功能:

  1. 使所有(列,行)对的唯一组合
  2. 将每个对表示为元组的字符串版本。这是克服LabelEncoder类不支持元组作为类名的一种变通方法。
  3. 将新项匹配到LabelEncoder

现在要使用这个新模型就有点复杂了。假设我们想要提取在前一个例子中查找的同一项的表示(df中的第一列)。列和第一行),我们可以这样做:

le.transform([str((df.columns[0], df.get_value(0, df.columns[0])))])
记住,现在每个查找都是一个元组的字符串表示 包含(列,行)

正如larsmans提到的,LabelEncoder()只接受一个一维数组作为参数。也就是说,可以很容易地滚动自己的标签编码器,对您选择的多个列进行操作,并返回转换后的数据框架。我在这里的代码部分基于Zac Stewart的优秀博客帖子发现在这里

创建自定义编码器只需要创建一个响应fit()transform()fit_transform()方法的类。对你来说,一个好的开始可能是这样的:

import pandas as pd
from sklearn.preprocessing import LabelEncoder
from sklearn.pipeline import Pipeline


# Create some toy data in a Pandas dataframe
fruit_data = pd.DataFrame({
'fruit':  ['apple','orange','pear','orange'],
'color':  ['red','orange','green','green'],
'weight': [5,6,3,4]
})


class MultiColumnLabelEncoder:
def __init__(self,columns = None):
self.columns = columns # array of column names to encode


def fit(self,X,y=None):
return self # not relevant here


def transform(self,X):
'''
Transforms columns of X specified in self.columns using
LabelEncoder(). If no columns specified, transforms all
columns in X.
'''
output = X.copy()
if self.columns is not None:
for col in self.columns:
output[col] = LabelEncoder().fit_transform(output[col])
else:
for colname,col in output.iteritems():
output[colname] = LabelEncoder().fit_transform(col)
return output


def fit_transform(self,X,y=None):
return self.fit(X,y).transform(X)
假设我们想对两个分类属性(fruitcolor)进行编码,同时保留数值属性weight。我们可以这样做:

MultiColumnLabelEncoder(columns = ['fruit','color']).fit_transform(fruit_data)

它将我们的fruit_data数据集从

enter image description here to

enter image description here

给它传递一个完全由分类变量组成的数据帧,省略columns参数将导致每一列都被编码(我相信这是你最初寻找的):

MultiColumnLabelEncoder().fit_transform(fruit_data.drop('weight',axis=1))

这个转换

enter image description here to

enter image description here

请注意,当它试图编码已经是数值的属性时可能会阻塞(如果您愿意,可以添加一些代码来处理这个问题)。

关于它的另一个很好的特性是我们可以在管道中使用这个自定义转换器:

encoding_pipeline = Pipeline([
('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
# add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)

你可以很容易地做到,

df.apply(LabelEncoder().fit_transform)

EDIT2:

在scikit-learn 0.20中,推荐的方法是

OneHotEncoder().fit_transform(df)

作为OneHotEncoder现在支持字符串输入。 使用ColumnTransformer仅对某些列应用OneHotEncoder是可能的

编辑:

由于这个最初的答案是一年多前的,并获得了许多赞(包括赏金),我可能应该进一步扩展它。

对于inverse_transform和transform,你需要做一点修改。

from collections import defaultdict
d = defaultdict(LabelEncoder)

这样,你现在将所有列LabelEncoder保留为字典。

# Encoding the variable
fit = df.apply(lambda x: d[x.name].fit_transform(x))


# Inverse the encoded
fit.apply(lambda x: d[x.name].inverse_transform(x))


# Using the dictionary to label future data
df.apply(lambda x: d[x.name].transform(x))

MOAR编辑:

使用Neuraxle的FlattenForEach步骤,也可以一次性对所有扁平数据使用相同的LabelEncoder:

FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df)

要根据数据列使用单独的__abc0,或者如果只有一些数据列需要进行标签编码,而其他数据列不需要,那么使用ColumnTransformer是一种解决方案,它允许对列选择和LabelEncoder实例进行更多控制。

这是一年半后的事实,但我也需要能够.transform()多个熊猫数据帧列一次(以及能够.inverse_transform()他们)。这扩展了上面@PriceHardman的优秀建议:

class MultiColumnLabelEncoder(LabelEncoder):
"""
Wraps sklearn LabelEncoder functionality for use on multiple columns of a
pandas dataframe.


"""
def __init__(self, columns=None):
self.columns = columns


def fit(self, dframe):
"""
Fit label encoder to pandas columns.


Access individual column classes via indexig `self.all_classes_`


Access individual column encoders via indexing
`self.all_encoders_`
"""
# if columns are provided, iterate through and get `classes_`
if self.columns is not None:
# ndarray to hold LabelEncoder().classes_ for each
# column; should match the shape of specified `columns`
self.all_classes_ = np.ndarray(shape=self.columns.shape,
dtype=object)
self.all_encoders_ = np.ndarray(shape=self.columns.shape,
dtype=object)
for idx, column in enumerate(self.columns):
# fit LabelEncoder to get `classes_` for the column
le = LabelEncoder()
le.fit(dframe.loc[:, column].values)
# append the `classes_` to our ndarray container
self.all_classes_[idx] = (column,
np.array(le.classes_.tolist(),
dtype=object))
# append this column's encoder
self.all_encoders_[idx] = le
else:
# no columns specified; assume all are to be encoded
self.columns = dframe.iloc[:, :].columns
self.all_classes_ = np.ndarray(shape=self.columns.shape,
dtype=object)
for idx, column in enumerate(self.columns):
le = LabelEncoder()
le.fit(dframe.loc[:, column].values)
self.all_classes_[idx] = (column,
np.array(le.classes_.tolist(),
dtype=object))
self.all_encoders_[idx] = le
return self


def fit_transform(self, dframe):
"""
Fit label encoder and return encoded labels.


Access individual column classes via indexing
`self.all_classes_`


Access individual column encoders via indexing
`self.all_encoders_`


Access individual column encoded labels via indexing
`self.all_labels_`
"""
# if columns are provided, iterate through and get `classes_`
if self.columns is not None:
# ndarray to hold LabelEncoder().classes_ for each
# column; should match the shape of specified `columns`
self.all_classes_ = np.ndarray(shape=self.columns.shape,
dtype=object)
self.all_encoders_ = np.ndarray(shape=self.columns.shape,
dtype=object)
self.all_labels_ = np.ndarray(shape=self.columns.shape,
dtype=object)
for idx, column in enumerate(self.columns):
# instantiate LabelEncoder
le = LabelEncoder()
# fit and transform labels in the column
dframe.loc[:, column] =\
le.fit_transform(dframe.loc[:, column].values)
# append the `classes_` to our ndarray container
self.all_classes_[idx] = (column,
np.array(le.classes_.tolist(),
dtype=object))
self.all_encoders_[idx] = le
self.all_labels_[idx] = le
else:
# no columns specified; assume all are to be encoded
self.columns = dframe.iloc[:, :].columns
self.all_classes_ = np.ndarray(shape=self.columns.shape,
dtype=object)
for idx, column in enumerate(self.columns):
le = LabelEncoder()
dframe.loc[:, column] = le.fit_transform(
dframe.loc[:, column].values)
self.all_classes_[idx] = (column,
np.array(le.classes_.tolist(),
dtype=object))
self.all_encoders_[idx] = le
return dframe.loc[:, self.columns].values


def transform(self, dframe):
"""
Transform labels to normalized encoding.
"""
if self.columns is not None:
for idx, column in enumerate(self.columns):
dframe.loc[:, column] = self.all_encoders_[
idx].transform(dframe.loc[:, column].values)
else:
self.columns = dframe.iloc[:, :].columns
for idx, column in enumerate(self.columns):
dframe.loc[:, column] = self.all_encoders_[idx]\
.transform(dframe.loc[:, column].values)
return dframe.loc[:, self.columns].values


def inverse_transform(self, dframe):
"""
Transform labels back to original encoding.
"""
if self.columns is not None:
for idx, column in enumerate(self.columns):
dframe.loc[:, column] = self.all_encoders_[idx]\
.inverse_transform(dframe.loc[:, column].values)
else:
self.columns = dframe.iloc[:, :].columns
for idx, column in enumerate(self.columns):
dframe.loc[:, column] = self.all_encoders_[idx]\
.inverse_transform(dframe.loc[:, column].values)
return dframe.loc[:, self.columns].values

例子:

如果dfdf_copy()是混合类型的pandas数据帧,你可以用以下方式将MultiColumnLabelEncoder()应用到dtype=object列:

# get `object` columns
df_object_columns = df.iloc[:, :].select_dtypes(include=['object']).columns
df_copy_object_columns = df_copy.iloc[:, :].select_dtypes(include=['object']).columns


# instantiate `MultiColumnLabelEncoder`
mcle = MultiColumnLabelEncoder(columns=object_columns)


# fit to `df` data
mcle.fit(df)


# transform the `df` data
mcle.transform(df)


# returns output like below
array([[1, 0, 0, ..., 1, 1, 0],
[0, 5, 1, ..., 1, 1, 2],
[1, 1, 1, ..., 1, 1, 2],
...,
[3, 5, 1, ..., 1, 1, 2],


# transform `df_copy` data
mcle.transform(df_copy)


# returns output like below (assuming the respective columns
# of `df_copy` contain the same unique values as that particular
# column in `df`
array([[1, 0, 0, ..., 1, 1, 0],
[0, 5, 1, ..., 1, 1, 2],
[1, 1, 1, ..., 1, 1, 2],
...,
[3, 5, 1, ..., 1, 1, 2],


# inverse `df` data
mcle.inverse_transform(df)


# outputs data like below
array([['August', 'Friday', '2013', ..., 'N', 'N', 'CA'],
['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
['August', 'Monday', '2014', ..., 'N', 'N', 'NJ'],
...,
['February', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
['March', 'Tuesday', '2013', ..., 'N', 'N', 'NJ']], dtype=object)


# inverse `df_copy` data
mcle.inverse_transform(df_copy)


# outputs data like below
array([['August', 'Friday', '2013', ..., 'N', 'N', 'CA'],
['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
['August', 'Monday', '2014', ..., 'N', 'N', 'NJ'],
...,
['February', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
['April', 'Tuesday', '2014', ..., 'N', 'N', 'NJ'],
['March', 'Tuesday', '2013', ..., 'N', 'N', 'NJ']], dtype=object)

你可以通过索引访问单独的列类、列标签和用于适合每个列的列编码器:

< p > mcle.all_classes_ < br > mcle.all_encoders_ < br > mcle.all_labels_ < br > < / p >

我们不需要LabelEncoder。

您可以将列转换为类别,然后获取它们的代码。我使用下面的字典推导将此过程应用于每一列,并将结果包装回具有相同索引和列名的相同形状的数据框架中。

>>> pd.DataFrame({col: df[col].astype('category').cat.codes for col in df}, index=df.index)
location  owner  pets
0         1      1     0
1         0      2     1
2         0      0     0
3         1      1     2
4         1      3     1
5         0      2     1

要创建映射字典,你可以使用字典理解式枚举类别:

>>> {col: {n: cat for n, cat in enumerate(df[col].astype('category').cat.categories)}
for col in df}


{'location': {0: 'New_York', 1: 'San_Diego'},
'owner': {0: 'Brick', 1: 'Champ', 2: 'Ron', 3: 'Veronica'},
'pets': {0: 'cat', 1: 'dog', 2: 'monkey'}}

这并没有直接回答你的问题(Naputipulu Jon和PriceHardman对此有精彩的回答)

但是,对于一些分类任务等,您可以使用

pandas.get_dummies(input_df)

这可以输入带有分类数据的数据框架,并返回带有二进制值的数据框架。变量值被编码到结果数据框架中的列名中。更多的

如果我们有单列来做标签编码和它的逆变换,当python中有多列时,很容易做到这一点

def stringtocategory(dataset):
'''
@author puja.sharma
@see The function label encodes the object type columns and gives label      encoded and inverse tranform of the label encoded data
@param dataset dataframe on whoes column the label encoding has to be done
@return label encoded and inverse tranform of the label encoded data.
'''
data_original = dataset[:]
data_tranformed = dataset[:]
for y in dataset.columns:
#check the dtype of the column object type contains strings or chars
if (dataset[y].dtype == object):
print("The string type features are  : " + y)
le = preprocessing.LabelEncoder()
le.fit(dataset[y].unique())
#label encoded data
data_tranformed[y] = le.transform(dataset[y])
#inverse label transform  data
data_original[y] = le.inverse_transform(data_tranformed[y])
return data_tranformed,data_original

根据对@PriceHardman的解决方案提出的评论,我建议该类的以下版本:

class LabelEncodingColoumns(BaseEstimator, TransformerMixin):
def __init__(self, cols=None):
pdu._is_cols_input_valid(cols)
self.cols = cols
self.les = {col: LabelEncoder() for col in cols}
self._is_fitted = False


def transform(self, df, **transform_params):
"""
Scaling ``cols`` of ``df`` using the fitting


Parameters
----------
df : DataFrame
DataFrame to be preprocessed
"""
if not self._is_fitted:
raise NotFittedError("Fitting was not preformed")
pdu._is_cols_subset_of_df_cols(self.cols, df)


df = df.copy()


label_enc_dict = {}
for col in self.cols:
label_enc_dict[col] = self.les[col].transform(df[col])


labelenc_cols = pd.DataFrame(label_enc_dict,
# The index of the resulting DataFrame should be assigned and
# equal to the one of the original DataFrame. Otherwise, upon
# concatenation NaNs will be introduced.
index=df.index
)


for col in self.cols:
df[col] = labelenc_cols[col]
return df


def fit(self, df, y=None, **fit_params):
"""
Fitting the preprocessing


Parameters
----------
df : DataFrame
Data to use for fitting.
In many cases, should be ``X_train``.
"""
pdu._is_cols_subset_of_df_cols(self.cols, df)
for col in self.cols:
self.les[col].fit(df[col])
self._is_fitted = True
return self

这个类适合编码器的训练集,并在转换时使用适合的版本。代码的初始版本可以在在这里中找到。

使用dict()实现LabelEncoder()多个列的简单方法:

from sklearn.preprocessing import LabelEncoder
le_dict = {col: LabelEncoder() for col in columns }
for col in columns:
le_dict[col].fit_transform(df[col])

并且你可以使用le_dict来对任何其他列进行labelEncode:

le_dict[col].transform(df_another[col])

可以直接在pandas中完成这一切,并且非常适合replace方法的独特功能。

首先,让我们创建一个字典的字典,将列及其值映射到新的替换值。

transform_dict = {}
for col in df.columns:
cats = pd.Categorical(df[col]).categories
d = {}
for i, cat in enumerate(cats):
d[cat] = i
transform_dict[col] = d


transform_dict
{'location': {'New_York': 0, 'San_Diego': 1},
'owner': {'Brick': 0, 'Champ': 1, 'Ron': 2, 'Veronica': 3},
'pets': {'cat': 0, 'dog': 1, 'monkey': 2}}

由于这将始终是一个一对一的映射,我们可以反转内部字典以获得新值到原始值的映射。

inverse_transform_dict = {}
for col, d in transform_dict.items():
inverse_transform_dict[col] = {v:k for k, v in d.items()}


inverse_transform_dict
{'location': {0: 'New_York', 1: 'San_Diego'},
'owner': {0: 'Brick', 1: 'Champ', 2: 'Ron', 3: 'Veronica'},
'pets': {0: 'cat', 1: 'dog', 2: 'monkey'}}

现在,我们可以使用replace方法的独特功能来获取一个嵌套的字典列表,并使用外部键作为列,而内部键作为我们想要替换的值。

df.replace(transform_dict)
location  owner  pets
0         1      1     0
1         0      2     1
2         0      0     0
3         1      1     2
4         1      3     1
5         0      2     1

我们可以通过再次链接replace方法轻松地返回到原始方法

df.replace(transform_dict).replace(inverse_transform_dict)
location     owner    pets
0  San_Diego     Champ     cat
1   New_York       Ron     dog
2   New_York     Brick     cat
3  San_Diego     Champ  monkey
4  San_Diego  Veronica     dog
5   New_York       Ron     dog

如果你有数值和类别两种类型的数据在数据帧 你可以使用:这里X是我的数据框架,有分类和数值两个变量

from sklearn import preprocessing
le = preprocessing.LabelEncoder()


for i in range(0,X.shape[1]):
if X.dtypes[i]=='object':
X[X.columns[i]] = le.fit_transform(X[X.columns[i]])

注意:如果你对转换它们不感兴趣,这个技巧是很好的。

在这里和其他地方对一些答案进行了大量的搜索和实验后,我认为你的答案是在这里:

< p > pd.DataFrame(列= df.columns, data = LabelEncoder () .fit_transform (df.values.flatten ()) .reshape (df.shape)) < / p >

这将跨列保留类别名称:

import pandas as pd
from sklearn.preprocessing import LabelEncoder


df = pd.DataFrame([['A','B','C','D','E','F','G','I','K','H'],
['A','E','H','F','G','I','K','','',''],
['A','C','I','F','H','G','','','','']],
columns=['A1', 'A2', 'A3','A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10'])


pd.DataFrame(columns=df.columns, data=LabelEncoder().fit_transform(df.values.flatten()).reshape(df.shape))


A1  A2  A3  A4  A5  A6  A7  A8  A9  A10
0   1   2   3   4   5   6   7   9   10  8
1   1   5   8   6   7   9   10  0   0   0
2   1   3   9   6   8   7   0   0   0   0

我检查了LabelEncoder的源代码(https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py)。它基于一组numpy变换,其中一个是np.unique()。这个函数只接受一维数组输入。(如果我说错了请指正)。

非常粗略的想法…… 首先,确定哪些列需要LabelEncoder,然后循环遍历每个列。

def cat_var(df):
"""Identify categorical features.


Parameters
----------
df: original df after missing operations


Returns
-------
cat_var_df: summary df with col index and col name for all categorical vars
"""
col_type = df.dtypes
col_names = list(df)


cat_var_index = [i for i, x in enumerate(col_type) if x=='object']
cat_var_name = [x for i, x in enumerate(col_names) if i in cat_var_index]


cat_var_df = pd.DataFrame({'cat_ind': cat_var_index,
'cat_name': cat_var_name})


return cat_var_df






from sklearn.preprocessing import LabelEncoder


def column_encoder(df, cat_var_list):
"""Encoding categorical feature in the dataframe


Parameters
----------
df: input dataframe
cat_var_list: categorical feature index and name, from cat_var function


Return
------
df: new dataframe where categorical features are encoded
label_list: classes_ attribute for all encoded features
"""


label_list = []
cat_var_df = cat_var(df)
cat_list = cat_var_df.loc[:, 'cat_name']


for index, cat_feature in enumerate(cat_list):


le = LabelEncoder()


le.fit(df.loc[:, cat_feature])
label_list.append(list(le.classes_))


df.loc[:, cat_feature] = le.transform(df.loc[:, cat_feature])


return df, label_list

返回的df将是编码后的那个,而label_list将显示所有这些值在相应列中的含义。 这是我为工作编写的数据处理脚本的一个片段。如果你觉得还有什么改进的地方,请告诉我。

编辑: 这里只想提一下,上述方法在处理数据帧时不会遗漏最佳数据。不确定它是如何工作的数据帧包含丢失的数据。(在执行上述方法之前,我已经处理了缺失过程)

主要使用@Alexander回答,但必须做一些更改-

cols_need_mapped = ['col1', 'col2']


mapper = {col: {cat: n for n, cat in enumerate(df[col].astype('category').cat.categories)}
for col in df[cols_need_mapped]}


for c in cols_need_mapped :
df[c] = df[c].map(mapper[c])

然后,为了将来重用,你可以将输出保存到json文档中,当你需要它时,你可以读入并使用.map()函数,就像我上面做的那样。

问题是你传递给fit函数的数据(pd dataframe)的形状。 你必须传递1d list。

因为scikit-learn 0.20,你可以使用sklearn.compose.ColumnTransformersklearn.preprocessing.OneHotEncoder:

如果你只有分类变量,OneHotEncoder直接:

from sklearn.preprocessing import OneHotEncoder


OneHotEncoder(handle_unknown='ignore').fit_transform(df)

如果你有异构类型的特性:

from sklearn.compose import make_column_transformer
from sklearn.preprocessing import RobustScaler
from sklearn.preprocessing import OneHotEncoder


categorical_columns = ['pets', 'owner', 'location']
numerical_columns = ['age', 'weigth', 'height']
column_trans = make_column_transformer(
(categorical_columns, OneHotEncoder(handle_unknown='ignore'),
(numerical_columns, RobustScaler())
column_trans.fit_transform(df)

文档中有更多选项:http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data

import pandas as pd
from sklearn.preprocessing import LabelEncoder


train=pd.read_csv('.../train.csv')


#X=train.loc[:,['waterpoint_type_group','status','waterpoint_type','source_class']].values
# Create a label encoder object
def MultiLabelEncoder(columnlist,dataframe):
for i in columnlist:


labelencoder_X=LabelEncoder()
dataframe[i]=labelencoder_X.fit_transform(dataframe[i])
columnlist=['waterpoint_type_group','status','waterpoint_type','source_class','source_type']
MultiLabelEncoder(columnlist,train)

在这里,我正在从位置读取一个csv,在函数中,我正在传递列列表,我想要labelencode和dataframe,我想应用这个。

这个怎么样?

def MultiColumnLabelEncode(choice, columns, X):
LabelEncoders = []
if choice == 'encode':
for i in enumerate(columns):
LabelEncoders.append(LabelEncoder())
i=0
for cols in columns:
X[:, cols] = LabelEncoders[i].fit_transform(X[:, cols])
i += 1
elif choice == 'decode':
for cols in columns:
X[:, cols] = LabelEncoders[i].inverse_transform(X[:, cols])
i += 1
else:
print('Please select correct parameter "choice". Available parameters: encode/decode')

这不是最有效的,但它工作,它是超级简单。

使用Neuraxle

TLDR;你可以在这里使用FlattenForEach包装器类简单地转换你的df: FlattenForEach(LabelEncoder(), then_unflatten=True).fit_transform(df)

使用这个方法,你的标签编码器将能够适应和转换在一个常规的scikit-learn管道。让我们简单地导入:

from sklearn.preprocessing import LabelEncoder
from neuraxle.steps.column_transformer import ColumnTransformer
from neuraxle.steps.loop import FlattenForEach

列的共享编码器相同:

下面是一个共享的LabelEncoder将如何应用于所有数据来编码:

    p = FlattenForEach(LabelEncoder(), then_unflatten=True)

结果:

    p, predicted_output = p.fit_transform(df.values)
expected_output = np.array([
[6, 7, 6, 8, 7, 7],
[1, 3, 0, 1, 5, 3],
[4, 2, 2, 4, 4, 2]
]).transpose()
assert np.array_equal(predicted_output, expected_output)

每列不同的编码器:

这里是第一个独立的LabelEncoder将如何应用于宠物,第二个将为列的所有者和位置共享。所以准确地说,我们这里有一个不同的和共享的标签编码器的组合:

    p = ColumnTransformer([
# A different encoder will be used for column 0 with name "pets":
(0, FlattenForEach(LabelEncoder(), then_unflatten=True)),
# A shared encoder will be used for column 1 and 2, "owner" and "location":
([1, 2], FlattenForEach(LabelEncoder(), then_unflatten=True)),
], n_dimension=2)

结果:

    p, predicted_output = p.fit_transform(df.values)
expected_output = np.array([
[0, 1, 0, 2, 1, 1],
[1, 3, 0, 1, 5, 3],
[4, 2, 2, 4, 4, 2]
]).transpose()
assert np.array_equal(predicted_output, expected_output)

如果你拥有object类型的所有特征,那么上面写的第一个答案https://stackoverflow.com/a/31939145/5840973很好。

但是,假设我们有混合类型的列。然后,我们可以以编程方式获取类型对象类型名称的特征列表,然后对它们进行标签编码。

#Fetch features of type Object
objFeatures = dataframe.select_dtypes(include="object").columns


#Iterate a loop for features of type object
from sklearn import preprocessing
le = preprocessing.LabelEncoder()


for feat in objFeatures:
dataframe[feat] = le.fit_transform(dataframe[feat].astype(str))
 



dataframe.info()

我们可以使用scikit learn中的OrdinalEncoder来代替LabelEncoder,它允许多列编码。

将分类特征编码为整数数组。 这个转换器的输入应该是一个类似数组的整数或字符串,表示分类(离散)特征所取的值。特征被转换为序号整数。这将导致每个特征的整数(0到n_categories - 1)的单列

>>> from sklearn.preprocessing import OrdinalEncoder
>>> enc = OrdinalEncoder()
>>> X = [['Male', 1], ['Female', 3], ['Female', 2]]
>>> enc.fit(X)
OrdinalEncoder()
>>> enc.categories_
[array(['Female', 'Male'], dtype=object), array([1, 2, 3], dtype=object)]
>>> enc.transform([['Female', 3], ['Male', 1]])
array([[0., 2.],
[1., 0.]])

描述和示例都是从它的文档页面复制的,你可以在这里找到:

https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html#sklearn.preprocessing.OrdinalEncoder

这是我解决你问题的办法。为了将包含文本的数据帧列转换为编码值,只需使用我的函数text_to_numbers,它返回LE的字典。键是列LabelEncoder ()作为值的列名。

def text_to_numbers(df):
le_dict = dict()
for i in df.columns:
if df[i].dtype not in ["float64", "bool", "int64"]:
le_dict[i] = preprocessing.LabelEncoder()
df[i] = le_dict[i].fit_transform(df[i])
    

return df, le_dict

下面的函数将使保留原始的未编码数据帧成为可能。

 def numbers_to_text(df, le_dict):
for i in le_dict.keys():
df[i] = le_dict[i].inverse_transform(df[i])
    

return df

下面是我一次性转换多列的解决方案,以及精确的inverse_transform

from sklearn import preprocessing
columns = ['buying','maint','lug_boot','safety','cls']  # columns names where transform is required
for X in columns:
exec(f'le_{X} = preprocessing.LabelEncoder()')  #create label encoder with name "le_X", where X is column name
exec(f'df.{X} = le_{X}.fit_transform(df.{X})')  #execute fit transform for column X with respective lable encoder "le_X", where X is column name
df.head()  # to display transformed results


for X in columns:
exec(f'df.{X} = le_{X}.inverse_transform(df.{X})')  #execute inverse_transform for column X with respective lable encoder "le_X", where X is column name
df.head() # to display Inverse transformed results of df

这是脚本

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
col_list = df.select_dtypes(include = "object").columns
for colsn in col_list:
df[colsn] = le.fit_transform(df[colsn].astype(str))