我试图使用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)
对于如何解决这个问题有什么想法吗?
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,我想应用这个。
正如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)
这是有可能做到这一切直接在熊猫,是非常适合的独特能力的替代方法。
首先,让我们创建一个字典的字典,将列及其值映射到新的替换值。
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
我们可以使用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