在pandas中使用任意优先级进行聚合

2024-05-15 07:34:53 发布

您现在位置:Python中文网/ 问答频道 /正文

给定数据帧

  Column1 Column2  Column3
0       a     foo        1
1       a     bar        2
2       b     baz       12
3       b     foo        4
4       c     bar        6
5       c     foo        3
6       c     baz        7
7       d     foo        9

我想按Column1分组,使用任意的优先顺序将值从column3中保留

例如,如果优先顺序为:

  1. 巴兹
  2. 酒吧

然后我希望输出显示为

         Column2
Column1         
a              2
b             12
c              7
d              9

“a”组保留“bar”值,因为“a”组没有“baz”,而“b”组保留“baz”值,依此类推

最优雅的方式是什么?现在,我正在应用一系列apply lambda来处理每一项,但感觉有些马虎

编辑: 如果进位跨越多个列怎么办

  Column1 Column2 Column3  Column4
0       a     foo    john        1
1       a     bar     jim        2
2       b     baz    jack       12
3       b     foo     jim        4
4       c     bar    john        6
5       c     foo    john        3
6       c     baz    jack        7
7       d     foo    jack        9

如果第2列和第3列的优先顺序为:

  1. 吉姆
  2. 巴兹

然后我希望输出显示为

        Column2  Column3
Column1                 
a           jim        2
b           jim        4
c           baz        7
d           foo        9

Tags: 数据foo顺序方式barbazjohn酒吧
3条回答

您可以使用map然后groupby+transform尝试以下逻辑

order = ['baz','bar','foo']
d = {v:k for k,v in dict(enumerate(order)).items()}
out = df.assign(k=df['Column2'].map(d))

print(df[out['k'].eq(out.groupby("Column1")['k'].transform("min"))])

  Column1 Column2  Column3
1       a     bar        2
2       b     baz       12
6       c     baz        7
7       d     foo        9

对于多列,使用与上述相同的逻辑进行编辑,方法如下:

order = ['jim','baz','foo']
d = {i:e for e,i in enumerate(order)}

s = df[['Column2','Column3']].replace(d).apply(pd.to_numeric,errors='coerce').min(1)

out = (s[s.eq(s.groupby(df['Column1']).transform("min"))]
       .replace(dict(enumerate(order))).rename("Col"))

df.loc[out.index,["Column1","Column4"]].join(out)

  Column1  Column4  Col
1       a        2  jim
3       b        4  jim
6       c        7  baz
7       d        9  foo

您可以尝试将Column2转换为分类:

df['Column2'] = pd.Categorical(df['Column2'], ordered=True, categories=['baz','bar','foo'])

df.sort_values(['Column1','Column2']).drop_duplicates('Column1')

输出:

  Column1 Column2  Column3
1       a     bar        2
2       b     baz       12
6       c     baz        7
7       d     foo        9

如果对“Column2”中的所有值都有一个顺序,则可以在设置索引后使用loc来强制执行自定义顺序,然后drop_duplicates只保留最高优先级

order = ['baz', 'bar', 'foo']
df.set_index('Column2').loc[order].drop_duplicates('Column1')

        Column1  Column3
Column2                 
baz           b       12
baz           c        7
bar           a        2
foo           d        9

在第二种情况下,如果需要跨多个列执行此操作,我们首先melt将Column2和Column3堆叠成一个长系列,其余的如下所示:

order = ['jim', 'baz', 'foo']
(df.melt(id_vars=['Column4', 'Column1'], value_vars=['Column2', 'Column3'])
   .drop(columns='variable')
   .set_index('value')
   .loc[order]
   .drop_duplicates('Column1')
)

       Column4 Column1
value                 
jim          2       a
jim          4       b
baz          7       c
foo          9       d

相关问题 更多 >