Bry*_*yan 192 python pandas 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)
Run Code Online (Sandbox Code Playgroud)
回溯(最近一次调用最后一次):文件"",第1行,在文件"/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py",第103行,in y y = column_or_1d(Y,警告=真)文件 "/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py",线306,在column_or_1d提高ValueError异常("坏输入形状{ 0.".format(shape))ValueError:输入形状错误(6,3)
有关如何解决这个问题的任何想法?
Nap*_*Jon 401
你可以轻松地做到这一点,
df.apply(LabelEncoder().fit_transform)
Run Code Online (Sandbox Code Playgroud)
编辑:
由于这个答案是在一年多以前,并产生了许多赞成票(包括赏金),我应该进一步扩展这一点.
对于inverse_transform和transform,你必须做一些hack.
OneHotEncoder().fit_transform(df)
Run Code Online (Sandbox Code Playgroud)
有了这个,您现在将所有列保留LabelEncoder为字典.
from collections import defaultdict
d = defaultdict(LabelEncoder)
Run Code Online (Sandbox Code Playgroud)
Pri*_*man 85
正如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)
Run Code Online (Sandbox Code Playgroud)
假设我们想要编码我们的两个分类属性(fruit和color),同时保留数字属性weight.我们可以这样做:
MultiColumnLabelEncoder(columns = ['fruit','color']).fit_transform(fruit_data)
Run Code Online (Sandbox Code Playgroud)
这会转换我们的fruit_data数据集
至

传递一个完全由分类变量组成的数据框并省略columns参数将导致每个列都被编码(我认为这是你最初寻找的):
MultiColumnLabelEncoder().fit_transform(fruit_data.drop('weight',axis=1))
Run Code Online (Sandbox Code Playgroud)
这转变了
至
.
请注意,当它尝试编码已经是数字的属性时,它可能会窒息(如果你愿意,可以添加一些代码来处理这个).
另一个很好的功能是我们可以在管道中使用这个自定义变换器:
encoding_pipeline = Pipeline([
('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
# add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)
Run Code Online (Sandbox Code Playgroud)
Ale*_*der 16
我们不需要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
Run Code Online (Sandbox Code Playgroud)
要创建映射字典,您可以使用字典理解来枚举类别:
>>> {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'}}
Run Code Online (Sandbox Code Playgroud)
ogr*_*sel 12
从scikit-learn 0.20开始,您可以使用sklearn.compose.ColumnTransformer和sklearn.preprocessing.OneHotEncoder:
如果只有分类变量,则OneHotEncoder直接:
from sklearn.preprocessing import OneHotEncoder
OneHotEncoder(handle_unknown='ignore').fit_transform(df)
Run Code Online (Sandbox Code Playgroud)
如果您具有异构类型的功能:
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)
Run Code Online (Sandbox Code Playgroud)
文档中的更多选项:http : //scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data
这是一年半之后的事实,但我也需要能够同时处理.transform()多个 Pandas 数据框列(并且也能够处理.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
Run Code Online (Sandbox Code Playgroud)
例子:
如果df和df_copy()是混合型pandasdataframes,您可以应用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)
Run Code Online (Sandbox Code Playgroud)
您可以通过索引访问用于拟合每列的各个列类、列标签和列编码器:
mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_
这并没有直接回答你的问题(Naputipulu Jon和PriceHardman对此有很棒的回复)
但是,出于少数分类任务的目的,您可以使用
pandas.get_dummies(input_df)
Run Code Online (Sandbox Code Playgroud)
这可以输入带有分类数据的数据帧,并返回带有二进制值的数据帧.变量值在结果数据帧中编码为列名.更多
假设您只是尝试获取一个sklearn.preprocessing.LabelEncoder()可用于表示您的列的对象,那么您要做的就是:
le.fit(df.columns)
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,您将有一个对应于每一列的唯一编号。更准确地说,你将有一个1:1映射df.columns到le.transform(df.columns.get_values())。要获取列的编码,只需将其传递给le.transform(...)。例如,以下将获取每一列的编码:
le.transform(df.columns.get_values())
Run Code Online (Sandbox Code Playgroud)
假设要sklearn.preprocessing.LabelEncoder()为所有行标签创建一个对象,可以执行以下操作:
le.fit([y for x in df.get_values() for y in x])
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您很可能具有非唯一的行标签(如您的问题所示)。要查看编码器创建的类,可以执行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])])
Run Code Online (Sandbox Code Playgroud)
您在评论中遇到的问题比较复杂,但仍然可以解决:
le.fit([str(z) for z in set((x[0], y) for x in df.iteritems() for y in x[1])])
Run Code Online (Sandbox Code Playgroud)
上面的代码执行以下操作:
LabelEncoder不支持将元组用作类名的类。LabelEncoder。现在使用这种新模型要复杂一些。假设我们要提取在上一个示例中查找的相同项目的表示形式(df.columns中的第一列和第一行),我们可以这样做:
le.transform([str((df.columns[0], df.get_value(0, df.columns[0])))])
Run Code Online (Sandbox Code Playgroud)
请记住,每个查找现在都是包含(列,行)的元组的字符串表示形式。
这是脚本
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))
Run Code Online (Sandbox Code Playgroud)
不,LabelEncoder不这样做。它接受一维数组的类标签,并生成一维数组。它旨在处理分类问题中的类标签,而不是任意数据,并且任何试图将其用于其他用途的尝试都将需要代码将实际问题转换为要解决的问题(并将解决方案还原到原始空间)。
可以直接在 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}}
Run Code Online (Sandbox Code Playgroud)
由于这将始终是一对一映射,因此我们可以反转内部字典以将新值映射回原始值。
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'}}
Run Code Online (Sandbox Code Playgroud)
现在,我们可以使用该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
Run Code Online (Sandbox Code Playgroud)
我们可以通过再次链接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
Run Code Online (Sandbox Code Playgroud)
如果数据框中有数字和分类两种类型的数据,您可以使用:这里 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]])
Run Code Online (Sandbox Code Playgroud)
注意:如果您对将它们转换回来不感兴趣,则此技术很好。
经过大量搜索和实验,在这里和其他地方找到了一些答案,我想你的答案就在这里:
pd.DataFrame(columns=df.columns, data=LabelEncoder().fit_transform(df.values.flatten()).reshape(df.shape))
这将保留跨列的类别名称:
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
Run Code Online (Sandbox Code Playgroud)
我检查了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
Run Code Online (Sandbox Code Playgroud)
返回的df将是编码后的 df,label_list将向您显示所有这些值在相应列中的含义。这是我为工作编写的数据处理脚本的片段。如果您认为还可以进一步改进,请告诉我。
编辑:只想在这里提一下,上面的方法适用于数据框架,不会错过最好的。不确定它如何处理包含丢失数据的数据框。(在执行上述方法之前我处理了丢失的程序)
| 归档时间: |
|
| 查看次数: |
140179 次 |
| 最近记录: |