给定一个有ID列和相应值列的DataFrame,我如何在重复ID的块中聚合(比如说求和)值?
示例DF。
import numpy as np
import pandas as pd
df = pd.DataFrame(
{'id': ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'a', 'a', 'b', 'a', 'b', 'b', 'b'],
'v': np.ones(15)}
)
请注意,只有两个唯一的ID,所以一个简单的... groupby('id')
不会用。而且,IDs也不会有规律地交替重复。我想出的办法是重新创建索引,来表示改变了的ID的块。
# where id changes:
m = [True] + list(df['id'].values[:-1] != df['id'].values[1:])
# generate a new index from m:
idx, i = [], -1
for b in m:
if b:
i += 1
idx.append(i)
# set as index:
df = df.set_index(np.array(idx))
# now I can use groupby:
df.groupby(df.index)['v'].sum()
# 0 5.0
# 1 3.0
# 2 2.0
# 3 1.0
# 4 1.0
# 5 3.0
这种重新创建索引的方法,让人感觉有点... 殊不知 pandas
. 我错过了什么?有没有更好的方法?
这里需要创建辅助程序 Series
与比较移位值的不等式比较 ne
累计金额,并传递给 groupby
,因为 id
列表中的列可以一起传递,将第一级的MultiIndex由第一级删除。reset_index(level=0, drop=True)
然后将索引转换为列 id
:
print (df['id'].ne(df['id'].shift()).cumsum())
0 1
1 1
2 1
3 1
4 1
5 2
6 2
7 2
8 3
9 3
10 4
11 5
12 6
13 6
14 6
Name: id, dtype: int32
df1 = (df.groupby([df['id'].ne(df['id'].shift()).cumsum(), 'id'])['v'].sum()
.reset_index(level=0, drop=True)
.reset_index())
print (df1)
id v
0 a 5.0
1 b 3.0
2 a 2.0
3 b 1.0
4 a 1.0
5 b 3.0
另一个想法是使用GroupBy.agg
词条和合计 id
逐列 GroupBy.first
:
df1 = (df.groupby(df['id'].ne(df['id'].shift()).cumsum(), as_index=False)
.agg({'id':'first', 'v':'sum'}))