我试图使用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 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])))])
记住,现在每个查找都是一个元组的字符串表示
包含(列、行)。
从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
正如larsmans提到的,LabelEncoder()只接受1维数组作为参数。也就是说,可以很容易地滚动自己的标签编码器,对您选择的多个列进行操作,并返回转换后的数据框架。我在这里的代码部分基于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)
假设我们想对两个分类属性(fruit和color)进行编码,而不使用数字属性权重。我们可以这样做:
MultiColumnLabelEncoder(columns = ['fruit','color']).fit_transform(fruit_data)
它转换了我们的fruit_data数据集
to
传递给它一个完全由分类变量组成的数据框架,省略columns参数将导致每个列都被编码(我相信这是你最初寻找的):
MultiColumnLabelEncoder().fit_transform(fruit_data.drop('weight',axis=1))
这个转换
to
.
请注意,当它试图编码已经是数值的属性时可能会阻塞(如果您愿意,可以添加一些代码来处理这个问题)。
另一个很好的特性是我们可以在管道中使用这个自定义转换器:
encoding_pipeline = Pipeline([
('encoding',MultiColumnLabelEncoder(columns=['fruit','color']))
# add more pipeline steps as needed
])
encoding_pipeline.fit_transform(fruit_data)