在 Pandas 中反转“独热”编码
- 2025-02-27 09:07:00
- admin 原创
- 57
问题描述:
我想要从这个基本上是独热编码的数据框开始。
In [2]: pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]})
Out[2]:
fox monkey rabbit
0 0 0 1
1 0 1 0
2 1 0 0
3 0 0 0
4 0 0 0
对于这个“反向”独热编码。
In [3]: pd.DataFrame({"animal":["monkey","rabbit","fox"]})
Out[3]:
animal
0 monkey
1 rabbit
2 fox
我想象可以巧妙地使用 apply 或 zip 来进行稀释,但我不确定如何...有人可以帮忙吗?
我尝试使用索引等方法来解决这个问题,但是并没有取得多大成功。
解决方案 1:
更新:正如 Henry Ecker 在他的回答中提到的那样,从 Pandas 1.5.0 开始,有一个原生的 Pandas 方法可以做到这一点 - pandas.from_dummies()
演示:
In [35]: s = pd.Series(['dog', 'cat', 'dog', 'bird', 'fox', 'dog'])
In [36]: dummies = pd.get_dummies(s)
In [37]: dummies
Out[37]:
bird cat dog fox
0 0 0 1 0
1 0 1 0 0
2 0 0 1 0
3 1 0 0 0
4 0 0 0 1
5 0 0 1 0
In [38]: pd.from_dummies(dummies)
Out[38]:
0 dog
1 cat
2 dog
3 bird
4 fox
5 dog
注意:pd.from_dummies()
如果使用参数创建虚拟对象,则可能无法正常工作,drop_first=True
例如:pd.get_dummies(data, drop_first=True)
演示:
In [39]: dummies = pd.get_dummies(s, drop_first=True)
In [40]: dummies
Out[40]:
cat dog fox
0 0 1 0
1 1 0 0
2 0 1 0
3 0 0 0
4 0 0 1
5 0 1 0
In [41]: pd.from_dummies(dummies)
...
ValueError: Dummy DataFrame contains unassigned value(s); First instance in row: 3
旧答案:我认为ayhan是正确的,应该是:
df.idxmax(axis=1)
这将为每行选择一个列标签,其中标签具有最大值。由于数据为 1 和 0,因此它将选择 1 的位置。
演示:
In [40]: s = pd.Series(['dog', 'cat', 'dog', 'bird', 'fox', 'dog'])
In [41]: s
Out[41]:
0 dog
1 cat
2 dog
3 bird
4 fox
5 dog
dtype: object
In [42]: pd.get_dummies(s)
Out[42]:
bird cat dog fox
0 0.0 0.0 1.0 0.0
1 0.0 1.0 0.0 0.0
2 0.0 0.0 1.0 0.0
3 1.0 0.0 0.0 0.0
4 0.0 0.0 0.0 1.0
5 0.0 0.0 1.0 0.0
In [43]: pd.get_dummies(s).idxmax(1)
Out[43]:
0 dog
1 cat
2 dog
3 bird
4 fox
5 dog
dtype: object
解决方案 2:
我将使用 apply 来解码列:
In [2]: animals = pd.DataFrame({"monkey":[0,1,0,0,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0]})
In [3]: def get_animal(row):
...: for c in animals.columns:
...: if row[c]==1:
...: return c
In [4]: animals.apply(get_animal, axis=1)
Out[4]:
0 rabbit
1 monkey
2 fox
3 None
4 None
dtype: object
解决方案 3:
这适用于单个标签和多个标签。
我们可以使用高级索引来解决这个问题。这是链接。
import pandas as pd
df = pd.DataFrame({"monkey":[1,1,0,1,0],"rabbit":[1,1,1,1,0],\n "fox":[1,0,1,0,0], "cat":[0,0,0,0,1]})
df['tags']='' # to create an empty column
for col_name in df.columns:
df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name
print df
结果是:
cat fox monkey rabbit tags
0 0 1 1 1 fox monkey rabbit
1 0 0 1 1 monkey rabbit
2 0 1 0 1 fox rabbit
3 0 0 1 1 monkey rabbit
4 1 0 0 0 cat
解释:我们迭代数据框上的列。
df.ix[selection criteria, columns to write value] = value
df.ix[df[col_name]==1,'tags']= df['tags']+' '+col_name
上面这一行基本上找到了 df[col_name] == 1 的所有位置,选择列“tags”并将其设置为 RHS 值,即 df['tags']+' '+ col_name
注意: .ix
自 Pandas v0.20 起已弃用。您应根据需要使用.loc
或.iloc
。
解决方案 4:
从pandas 1.5.0开始,直接支持反转独热编码pandas.from_dummies
:
import pandas as pd # v 1.5.0
onehot_df = pd.DataFrame({
"monkey": [0, 1, 0],
"rabbit": [1, 0, 0],
"fox": [0, 0, 1]
})
new_df = pd.from_dummies(onehot_df)
#
# 0 rabbit
# 1 monkey
# 2 fox
生成的 DataFrame 似乎没有列标题(它是一个空字符串)。为了解决这个问题,rename
后面的列from_dummies
new_df = pd.from_dummies(onehot_df).rename(columns={'': 'animal'})
# animal
# 0 rabbit
# 1 monkey
# 2 fox
或者,如果 DataFrame 已经定义了分隔列(例如由 生成的独热编码pandas.get_dummies
),例如
import pandas as pd # v 1.5.0
onehot_df = pd.DataFrame({
'animal_fox': [0, 0, 1],
'animal_monkey': [0, 1, 0],
'animal_rabbit': [1, 0, 0]
})
# animal_fox animal_monkey animal_rabbit
# 0 0 0 1
# 1 0 1 0
# 2 1 0 0
只需指定sep
反转编码
new_df = pd.from_dummies(onehot_df, sep='_')
# animal
# 0 rabbit
# 1 monkey
# 2 fox
分隔符第一个实例之前的字符串sep
将成为新 DataFrame 中的列标题(在本例中为“animal”),字符串的其余部分将成为列值(在本例中为“rabbit”、“monkey”、“fox”)。
解决方案 5:
我会这么做:
cols = df.columns.to_series().values
pd.DataFrame(np.repeat(cols[None, :], len(df), 0)[df.astype(bool).values], df.index[df.any(1)])
定时
MaxU 的方法对大型数据帧有优势
小df
5 x 3
大df
1000000 x 52
解决方案 6:
您可以尝试使用melt()
。当一行有多个 OHE 标签时,此方法也有效。
# Your OHE dataframe
df = pd.DataFrame({"monkey":[0,1,0],"rabbit":[1,0,0],"fox":[0,0,1]})
mel = df.melt(var_name=['animal'], value_name='value') # Melting
mel[mel.value == 1].reset_index(drop=True) # this gives you the result
解决方案 7:
尝试一下:
df = pd.DataFrame({"monkey":[0,1,0,1,0],"rabbit":[1,0,0,0,0],"fox":[0,0,1,0,0], "cat":[0,0,0,0,1]})
df
cat fox monkey rabbit
0 0 0 0 1
1 0 0 1 0
2 0 1 0 0
3 0 0 1 0
4 1 0 0 0
pd.DataFrame([x for x in np.where(df ==1, df.columns,'').flatten().tolist() if len(x) >0],columns= (["animal"]) )
animal
0 rabbit
1 monkey
2 fox
3 monkey
4 cat
解决方案 8:
只需在数据框上简单应用即可实现
# function to get column name with value one for each row in dataframe
def get_animal(row):
return(row.index[row.apply(lambda x: x==1)][0])
# prepare a animal column
df['animal'] = df.apply(lambda row:get_animal(row), axis=1)
解决方案 9:
一种无需 for 循环即可处理多个标签的方法。结果将是一个列表列。如果每行的标签数量相同,则可以添加result_type='expand'
以获得多列。
df.apply(lambda x: df.columns[x==1], axis=1)
扫码咨询,免费领取项目管理大礼包!