给定这个数据帧:
df = pd.DataFrame([[1,1],[2,2],[2,3],[2,3],[2,4]], columns = ['A','B'])
df
A B
0 1 1
1 2 2
2 2 3
3 2 3
4 2 4
我想使用 A 列上的 groupby
和 B 列上的 apply
在 B 中尝试不同的聚合值集合
如果我将 B 作为列表收集,这将按预期工作:
df.groupby('A')['B'].apply(list).reset_index(name='list')
A list
0 1 [1]
1 2 [2, 3, 3, 4]
如果我将 B 作为集合收集,这将按预期工作:
df.groupby('A')['B'].apply(set).reset_index(name='set')
A set
0 1 {1}
1 2 {2, 3, 4}
我(天真地)会期望 Counter 类以相同的方式工作:
from collections import Counter
Counter([2, 3, 3, 4])
Counter({2: 1, 3: 2, 4: 1})
但是当我尝试使用 Counter 时,它的行为相当出乎意料,就像我使用 set 或 list 一样:
df.groupby('A')['B'].apply(Counter).reset_index(name='counter')
A level_1 counter
0 1 1 1.0
1 1 2 NaN
2 1 3 NaN
3 1 4 NaN
4 2 1 NaN
5 2 2 1.0
6 2 3 2.0
7 2 4 1.0
我希望:
A counter
0 1 Counter({1: 1})
1 2 Counter({2: 1, 3: 2, 4: 1})
一个有趣的线索是:
df.groupby('A')['B'].apply(type).reset_index(name='type')
A type
0 1 <class 'pandas.core.series.Series'>
1 2 <class 'pandas.core.series.Series'>
但这如我所料:
Counter(pd.core.series.Series([2, 3, 3, 4]))
Counter({2: 1, 3: 2, 4: 1})
这不起作用:
def mycounter(series):
return Counter(list(series))
mycounter
df.groupby('A')['B'].apply(mycounter).reset_index(name='type')
A level_1 type
0 1 1 1.0
1 1 2 NaN
2 1 3 NaN
3 1 4 NaN
4 2 1 NaN
5 2 2 1.0
6 2 3 2.0
7 2 4 1.0
我有点怀疑 Pandas 有问题?
(添加):我刚试过这个,它有效。所以,我不确定为什么 apply
没有,而 agg
有:
df.groupby('A')['B'].agg([Counter]).reset_index()
A Counter
0 1 {1: 1}
1 2 {2: 1, 3: 2, 4: 1}
答案 0 :(得分:4)
df.groupby('A')['B'].agg(Counter).reset_index(name='counter')
A counter
0 1 {1: 1}
1 2 {2: 1, 3: 2, 4: 1}
apply
是一个有趣的函数,因为它可以生成聚合和非聚合结果。
运行:
df.groupby('A')['B'].apply(lambda x: {0: 1, 1: 2, 2: 3})
A
1 0 1
1 2
2 3
2 0 1
1 2
2 3
Name: B, dtype: int64
当从 dict
返回 apply
时,它会将键解释为 DataFrame 的索引。而不是将其解释为聚合值(如 agg
)。
因此为什么计数器被解释为:
A
1 1 1.0 # {1: 1} (index 1 value 1)
2 NaN
3 NaN
4 NaN
2 1 NaN
2 1.0 # {2: 1, 3: 2, 4: 1} (index 2 value 1)
3 2.0 # (index 3 value 2)
4 1.0 # (index 4 value 1)
Name: B, dtype: float64
但是,对于 agg
,预期返回单个值,因此 dict
被解释为单个单元:
运行:
df.groupby('A')['B'].agg(lambda x: {0: 1, 1: 2, 2: 3})
A
1 {0: 1, 1: 2, 2: 3}
2 {0: 1, 1: 2, 2: 3}
Name: B, dtype: object