在pandas中,如何在一个数据帧中对十组数据进行排序?

2024-06-13 22:29:50 发布

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

我有一个看起来像这样的数据帧:

import pandas as pd
import numpy as np
rand = np.random.RandomState(1)
df = pd.DataFrame({'A': ['foo', 'bar', 'baz'] * 10,
                   'B': [rand.choice(['cat', 'dog', 'fish', 'pig', 'cow']) for i in range(30)],
                   'C': 1})

>> df.head(5)
     A    B  C
0  foo  pig  1
1  bar  cow  1
2  baz  cat  1
3  foo  dog  1
4  bar  pig  1

然后我按不同的组合分组以得到计数,我按组降序排列,如下所示:

>> d = df.groupby(['A','B']).sum();
>> d = d.groupby(level=0, group_keys=False).apply(lambda x: x.sort_values('C', ascending=False)); d

          C
A   B      
bar dog   4
    cow   2
    fish  2
    cat   1
    pig   1
baz cow   4
    cat   3
    fish  2
    dog   1
foo dog   4
    cow   3
    pig   2
    cat   1

我现在想要的是,A组中的每一组,保留前2名,其余的汇总为“其他”。我有一个函数summarise(),它可以工作:

def summarise(l, n=10, name='Other'):
    h = l.head(n)

    idx = l.index[0]
    if isinstance(idx, (list, tuple)):
        prefix = list(idx[:-1])
    else:
        prefix = []
    return h.append(pd.DataFrame([l.tail(-n).sum()], columns=l.columns, index=[tuple(prefix+[name])]))

>> summarise(d, n=2)
            C
A   B        
bar dog     4
    cow     2
    Other  24

但如果我试着用apply来为每个小组做这件事,它就会爆炸。似乎函数被传递了一个Series?你知道吗

我想要的输出如下:

  A     B    C
bar   dog    4
bar   cow    2
bar   Other  4
baz   cow    4
baz   cat    3
baz   Other  3
foo   dog    4
foo   cow    3
foo   Other  3

我本以为d.groupby('A').tail(-2).sum()会起作用,但它没有达到我的预期。你知道吗

编辑:多亏了这些答案,我想出了以下功能,将来应该会对人们有所帮助。有点恼人的是,1列和更多列的情况是不同的,但就这样吧。支持每组前N名,但也支持截止百分比。有了这个功能,我可以在许多方面轻松地切片和骰子我的数据。你知道吗

def top_per_group(df, cols, n=None, p=None, name='Other'):
    d=df.groupby(cols).size().sort_values(ascending=False)
    if len(cols) > 1:
        d = d.sortlevel(0, sort_remaining=False)

    d = d.reset_index()

    if n:
        if len(cols) > 1:
            sel_list = d.groupby(cols[:-1]).cumcount()<n
        else:
            sel_list = d.index<n
    else:
        if len(cols) > 1:
            sel_list = d.groupby(cols[:-1])[0].apply(lambda x: x/float(x.sum())) >= p
        else:
            sel_list = d[0].div(d[0].sum()) >= p

    grouper = d[cols[-1]].where(sel_list, name)
    return d.groupby(cols[:-1] + [grouper], sort=False).sum().reset_index()

Tags: falsedfindexfoobarbazlistcat
1条回答
网友
1楼 · 发布于 2024-06-13 22:29:50

如果重置索引,则可以根据累计计数创建一个grouper:

d = d.reset_index()
grouper = d['B'].where(d.groupby('A').cumcount()<2, 'Other')
d.groupby(['A', grouper], sort=False).sum()
Out: 
           C
A   B       
bar dog    4
    cow    2
    Other  4
baz cow    4
    cat    3
    Other  3
foo dog    4
    cow    3
    Other  3

或者,使用重置索引:

d.groupby(['A', grouper], sort=False).sum().reset_index()
Out: 
     A      B  C
0  bar    dog  4
1  bar    cow  2
2  bar  Other  4
3  baz    cow  4
4  baz    cat  3
5  baz  Other  3
6  foo    dog  4
7  foo    cow  3
8  foo  Other  3

相关问题 更多 >