使用列名称作为值标签将多列合并为一个类别列

buh*_*htz 26 python pandas

我有这个数据

   ID      A      B      C
0   0   True  False  False
1   1  False   True  False
2   2  False  False   True
Run Code Online (Sandbox Code Playgroud)

并想把它改造成

   ID group
0   0     A
1   1     B
2   2     C
Run Code Online (Sandbox Code Playgroud)
  • 我想使用列名称作为category列的值标签。
  • 每行最多只有一个True值。

这是MWE

#!/usr/bin/env python3
import pandas as pd

df = pd.DataFrame({
    'ID': range(3),
    'A': [True, False, False],
    'B': [False, True, False],
    'C': [False, False, True]
})

result = pd.DataFrame({
    'ID': range(3),
    'group': ['A', 'B', 'C']
})
result.group = result.group.astype('category')

print(df)
print(result)
Run Code Online (Sandbox Code Playgroud)

我可以df.apply(lambda row: ...magic.., axis=1)。但是使用 pandas 自己的工具是否有更优雅的方式呢?

Nur*_*Taş 17

您可以使用df.dot

df['group'] = df[['A', 'B', 'C']].dot(df.columns[1:])
Run Code Online (Sandbox Code Playgroud)


sop*_*les 13

您可以使用以下命令pd.melt()来重塑和重命名,然后对“值”列进行布尔过滤query

pd.melt(df,id_vars=['ID'],var_name= 'group').query('value') 

   ID group  value
0   0     A   True
4   1     B   True
8   2     C   True
Run Code Online (Sandbox Code Playgroud)

链接.drop('value',axis=1).reset_index(drop=True)将给出您的最终输出:

   ID group
0   0     A
1   1     B
2   2     C
Run Code Online (Sandbox Code Playgroud)


Sco*_*ton 10

还有另一种方式:

df.set_index(['ID'])\
  .rename_axis('group', axis=1)\ # getting column name correct
  .stack()\                      # reshaping getting column headers into dataframe rows
  .loc[lambda x: x]\             # filtering for True
  .reset_index()\                # moving ID back into dataframe columns
  .drop(0, axis=1)               # dropping boolean column
Run Code Online (Sandbox Code Playgroud)

输出:

   ID group
0   0     A
1   1     B
2   2     C
Run Code Online (Sandbox Code Playgroud)


moz*_*way 9

比 更详细melt,但这会在重塑期间删除无效列:

(df.set_index('ID')
   .rename_axis(columns='group')
   .replace(False, pd.NA)
   .stack().reset_index().drop(columns=0)
)
Run Code Online (Sandbox Code Playgroud)

输出:

   ID group
0   0     A
1   1     B
2   2     C
Run Code Online (Sandbox Code Playgroud)


Arc*_*Pwn 7

您可以使用熔化,然后根据值为 true 的列进行查找以获得您期望的结果

df = df.melt(id_vars = 'ID', var_name = 'group')
df.loc[df['value'] == True][['ID', 'group']]
Run Code Online (Sandbox Code Playgroud)


Shu*_*rma 7

idxmax

s = df.set_index('ID')
s.idxmax(1).where(s.any(1))
Run Code Online (Sandbox Code Playgroud)
ID
0    A
1    B
2    C
dtype: object
Run Code Online (Sandbox Code Playgroud)