我试图使用scikit-learn的LabelEncoder来编码字符串标签的pandas 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)

回溯(最近一次调用): 文件“”,第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)

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


当前回答

我们可以使用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

其他回答

我查看了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将是编码后的df, label_list将显示所有这些值在相应列中的含义。 这是我为工作编写的数据处理脚本的一个片段。如果你觉得还有什么改进的地方,请告诉我。

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

如果我们有单列来做标签编码和它的逆变换,当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

从scikit-learn 0.20开始,你可以使用sklearn.compose.ColumnTransformer和sklearn.预处理. 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

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

le.fit(df.columns)

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

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

假设你想为你所有的行标签创建一个sklearn.预处理. 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. xml文件中第一列的标签。列数组和第一行,你可以这样做:

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

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

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

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

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

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

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

记住,现在每个查找都是一个元组的字符串表示 包含(列、行)。

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,我想应用这个。