同一数据帧上的多个总和

Posted

技术标签:

【中文标题】同一数据帧上的多个总和【英文标题】:Mutliple sums on the same dataframe 【发布时间】:2020-06-25 14:00:43 【问题描述】:

我正在尝试对同一个数据帧执行多个求和,然后将新数据帧连接到一个最终数据帧中。有没有一种简洁的方法,还是我需要使用迭代?

我有一个这种形式的字典 key: [list_of_idx], ... 并且需要按我的数据框为每个键分组。

样本数据

import random
random.seed(1)

df_len = 5
df = 'idx':i: i+1 for i in range(df_len), 'data':i:random.randint(1,11) for i in range(df_len)
df = pd.DataFrame(df).set_index('idx')

# Groups with the idx to groupby
groups = 'a': [1,2,3,4,5],
          'b': [1,4],
          'c': [5]

# I'm trying to avoid/find a faster way than this
dfs = []
for grp in groups:
    _df = df.loc[groups[grp]]
    _df['grp'] = grp
    _df = _df.groupby('grp').sum()

    dfs.append(_df)
dff = pd.concat(dfs)

输入(df)

   data  idx
0     2    1
1    10    2
2     9    3
3     3    4
4     6    5

预期输出 (dff)

     data
grp      
a      30
c       6
b       5

注意:我坚持使用 python 2.7 和 pandas 0.16.1

时间结果

我测试了建议的方法并计算了执行时间。我显示了每次执行的平均时间(每个答案使用 1000 次执行): 由于我的 pandas 版本,我无法测试 Quang Hoang 第一个答案。

time         method  
0.00696 sec  my method (question)  
0.00328 sec  piRSquared (pd.concat)  
0.00024 sec  piRSquared (collections and defaultdict)  
0.00444 sec  Quang Hoang (2nd method : concat + reindex)  

【问题讨论】:

我能说我很惊喜,真的很高兴看到有人遵循一些好的建议,你在这里使用random.seed(...),这样每个人都可以创建一个可重复的示例,同时仍然能够扩展输入/输出测试:) 【参考方案1】:

这应该(相当)快一点:

s = pd.Series(groups).explode()
df.reindex(s).groupby(s.index)['data'].sum()

输出:

a    30
b     5
c     6
Name: data, dtype: int64

更新:与早期 pandas 版本类似的方法,虽然它可能没有那么快

s = pd.concat([pd.DataFrame('grp':a, 'idx':b) for a,b in groups.items()],
             ignore_index=True).set_index('grp')
df.reindex(s.idx).groupby(s.index)['data'].sum()

【讨论】:

这很聪明(-: 感谢快速回答,不幸的是,我坚持使用 python 2.7 和 pandas 0.16.1 并且 .explode() 没有实现:(我将版本添加到我的帖子中【参考方案2】:

巧妙使用pd.concat

pd.concat(k: df.loc[v] for k, v in groups.items()).sum(level=0)

   data
a    22
b     8
c     2

注意:这神奇地适用于所有列。 假设我们有more_data

import random
random.seed(1)
df_len = 5
df = 
    'idx':i: i+1 for i in range(df_len),
    'data':i:random.randint(1,11) for i in range(df_len),
    'more_data':i:random.randint(1,11) for i in range(df_len),

df = pd.DataFrame(df).set_index('idx')

然后

pd.concat(k: df.loc[v] for k, v in groups.items()).sum(level=0)

   data  more_data
a    22         42
b     8         19
c     2          7

但我会坚持使用更多 Python:collections.defaultdict

from collections import defaultdict

results = defaultdict(int)

for k, V in groups.items():
    for v in V:
        results[k] += df.at[v, 'data']

pd.Series(results)

a    22
b     8
c     2
dtype: int64

为此,我必须将defaultdict 设置为稍有不同:

from collections import defaultdict

results = defaultdict(lambda: defaultdict(int))

for k, V in groups.items():
    for v in V:
        for c in df.columns:
            results[c][k] += df.at[v, c]

pd.DataFrame(results)

   data  more_data
a    22         42
b     8         19
c     2          7

这就是没有defaultdict 而是使用来自dict 对象的方法setdefault 的样子。

results = 

for k, V in groups.items():
    for v in V:
        for c in df.columns:
            results.setdefault(c, )
            results[c].setdefault(k, 0)
            results[c][k] += df.at[v, c]

pd.DataFrame(results)

   data  more_data
a    22         42
b     8         19
c     2          7

【讨论】:

我喜欢它适用于多列(使用 concat)的事实。可以对 defaultdict 做同样的事情吗? (我从来没用过。) 是的,这是可能的。让我把它的样子放在一起。 @Paulloed 我已经更新了帖子,为您提供了更多信息。 感谢您的准确回答! (在dict 上使用.setdefault() 似乎更快一些)

以上是关于同一数据帧上的多个总和的主要内容,如果未能解决你的问题,请参考以下文章

需要帮助在一个动态文本框中显示多个输入文本组件

多个表上的查询计数/总和

在具有多个参数的 pandas 数据帧上应用滚动函数

如何在聚合的 pandas 数据帧上运行多个函数

Pandas:np.where 在数据帧上有多个条件

在每一行数据帧上调用类似应用的函数,每行有多个参数