我试图使用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)
对于如何解决这个问题有什么想法吗?
在这里和其他地方进行了大量的搜索和实验后,我认为你的答案是:
pd.DataFrame(列= 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
假设你只是想获得一个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])))])
记住,现在每个查找都是一个元组的字符串表示
包含(列、行)。
这是有可能做到这一切直接在熊猫,是非常适合的独特能力的替代方法。
首先,让我们创建一个字典的字典,将列及其值映射到新的替换值。
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