同一数据帧上的多个总和
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()
似乎更快一些)以上是关于同一数据帧上的多个总和的主要内容,如果未能解决你的问题,请参考以下文章