Pandas按组分组并过滤计数

9
我希望捕获一些分类值,这些值的出现频率高于某个特定阈值:
df:
ticket_id,  category,  amount --> some more columns
1020        cat1       1000
1022        cat1       55
1023        cat1       12291
1120        cat2       140
1121        cat3       1250 
^
|
|
Way more rows with mostly (1020) cat5, (98) cat1, cat3, cat4 and no cat2.

>>>> df.groupby('category')['amount'].count()
category
cat1       100
cat2       1
cat3       6
cat4       2
cat5       1020

我希望能够把数量大于20的分类列出来。目前我的做法是:

>>>> t = test.groupby('disposition')['fine_amount'].agg(['count','mean'])
>>>> t[t['count']>10].index.values
array(['cat1','cat5'])

现在这样可以工作,但我相信可以更简短地完成:为了引用计数列,我需要至少2个聚合函数,此外还需要1个变量和2行代码。 我希望可以有以下简洁的写法:

>>>> groupby('category')['amount'].apply(lambda x: x.count() > 10)

但是这将产生以下结果:
cat1    100   True
etc

>>>> groupby('category')['amount'].apply(lambda x: x[x.count() > 10])
Fails completely

>>>> groupby('category')['amount'].count().nlargest(2)
gives the correct list but in this case because I know there are 2 elements.

什么是最优雅/性能最佳的解决方案?

1
你能发布一下最初的数据框吗?或者至少发布一个小样本吗? - user3483203
建议重新命名,因为标题并不反映实际问题,而且答案也没有回答标题中的问题。这意味着在搜索标题中的问题时会出现此页面,但是该页面并未回答该问题。 - Robert P. Goldman
@RobertP.Goldman 英语不是我的母语,但我认为标题和答案在2年后仍然准确。我可以想象其他问题可能有相同的标题,但这是SO。诚然,6k的浏览量和2个赞并不表示一个非常复杂的问题。如果我看到更多人对您的评论点赞或者您提供了建设性的替代方案,我会重新考虑标题的。 - dr jerry
1
@drjerry 问题在于没有一个回答解决了你所问的问题。在这两个答案中,都添加了新列和索引,而没有使用 group by 和按计数过滤。我能想到的最好的方法是 new_df = new_df.groupby(["col1", "col2"]).filter(lambda x: len(x) >= 10_000),但我不知道这是否是一个好答案。使用 len 进行计数可能不是最佳解决方案。 - Robert P. Goldman
2个回答

18

通过使用初始groupby的结果并索引它,您可以使其更加简洁:

设置

categories = ['cat1', 'cat2', 'cat3', 'cat4', 'cat5']
dct = {'categories': [random.choice(categories) for i in range(75)], 'amount': [random.randint(1, 10) for _ in range(75)]}
df = pd.DataFrame(dct)

groupbycount

s = df.groupby('categories').amount.count()

# categories
# cat1    12
# cat2    10
# cat3    21
# cat4    17
# cat5    15
# Name: amount, dtype: int64

简洁明了的索引:

s[s > 20].index.tolist()
['cat3']

仍然只有2行代码和1个变量,但是两个聚合函数已经被删除了。 - dr jerry

6
你可以在布尔索引中使用 Lambda 表达式:
借鉴 @user2483203 的设置:
np.random.seed(123)
categories = ['cat1', 'cat2', 'cat3', 'cat4', 'cat5']
dct = {'categories': [np.random.choice(categories) for i in range(100)], 'amount': [np.random.randint(1, 10) for _ in range(100)]}
df = pd.DataFrame(dct)

使用value_counts和布尔索引:
df['categories'].value_counts()[lambda x: x>20].index.tolist()

输出:

['cat4', 'cat2']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接