Python字典分组并对多个值求和

5

我有一组数据,格式为字典列表如下:

data = [
    {'name': 'A', 'tea':5, 'coffee':6},
    {'name': 'A', 'tea':2, 'coffee':3},
    {'name': 'B', 'tea':7, 'coffee':1},
    {'name': 'B', 'tea':9, 'coffee':4},
]

我将尝试按照“名称”进行分组,并分别对“茶”和“咖啡”进行求和。

最终分组数据必须采用以下格式:

grouped_data = [
    {'name': 'A', 'tea':7, 'coffee':9},
    {'name': 'B', 'tea':16, 'coffee':5},
]

我尝试了一些步骤:

from collections import Counter
c = Counter()
for v in data:
    c[v['name']] += v['tea']

my_data = [{'name': name, 'tea':tea} for name, tea in c.items()]
for e in my_data:
    print e

上述步骤返回了以下输出:
{'name': 'A', 'tea':7,}
{'name': 'B', 'tea':16}

我只能对“茶”这个键进行求和,无法对“咖啡”这个键进行求和,你们能否帮忙解决这个问题,以获得分组数据格式。


1
你为什么要使用Counter?为什么不直接使用字典? - blacksite
请查看zip函数 https://docs.python.org/3.4/library/functions.html#zip - Grynets
@blacksite 感谢您的回复,我尝试了那个方法,但是我无法得到解决方案。 - Ajay Kumar
你使用pandas吗?只需要几行代码。 - cs95
@AjayKumar 请看答案,使用 df.to_dict - cs95
显示剩余2条评论
5个回答

10
使用 pandas
df = pd.DataFrame(data)
df

   coffee name  tea
0       6    A    5
1       3    A    2
2       1    B    7
3       4    B    9


g = df.groupby('name', as_index=False).sum()
g

  name  coffee  tea
0    A       9    7
1    B       5   16

最后一步是df.to_dict

d = g.to_dict('r')

d
[{'coffee': 9, 'name': 'A', 'tea': 7}, {'coffee': 5, 'name': 'B', 'tea': 16}]

@COLDSPEED,非常感谢你的回答,我在我的代码中忘记了加上 'as_index=False',现在它已经正常运行了。 - Ajay Kumar
该死... 差一点就得到了相同的结果,但忘记了 as_index! - blacksite

2
您可以尝试以下方法:
data = [
{'name': 'A', 'tea':5, 'coffee':6},
{'name': 'A', 'tea':2, 'coffee':3},
{'name': 'B', 'tea':7, 'coffee':1},
{'name': 'B', 'tea':9, 'coffee':4},
]
import itertools
final_data = [(a, list(b)) for a, b in itertools.groupby([i.items() for i in data], key=lambda x:dict(x)["name"])] 
new_final_data = [{i[0][0]:sum(c[-1] for c in i if isinstance(c[-1], int)) if i[0][0] != "name" else i[0][-1] for i in zip(*b)} for a, b in final_data]

输出:

[{'tea': 7, 'coffee': 9, 'name': 'A'}, {'tea': 16, 'coffee': 5, 'name': 'B'}

1
使用pandas,这很容易做到:

import pandas as pd

data = [
    {'name': 'A', 'tea':5, 'coffee':6},
    {'name': 'A', 'tea':2, 'coffee':3},
    {'name': 'B', 'tea':7, 'coffee':1},
    {'name': 'B', 'tea':9, 'coffee':4},
]

df = pd.DataFrame(data)
df.groupby(['name']).sum()

      coffee  tea
name             
A          9    7
B          5   16

这是将其转换为字典格式的一种方法:

grouped_data = []
for idx in gb.index:
    d = {'name': idx}
    d = {**d, **{col: gb.loc[idx, col] for col in gb}}
    grouped_data.append(d)


grouped_data
Out[15]: [{'coffee': 9, 'name': 'A', 'tea': 7}, {'coffee': 5, 'name': 'B', 'tea': 16}]

但是COLDSPEED使用 as_index=False 配置,得到了本地熊猫解决方案...

谢谢您的回复,我也尝试使用pandas并且已经做到了这一步,但是我无法将数据框转换为我期望的字典格式。 - Ajay Kumar
谢谢,这个解决方案也有效。 - Ajay Kumar

1

@karthick reddy,谢谢。我也尝试了这些步骤,但是我无法将数据框转换为我期望的字典格式,现在我找到了解决方案。 - Ajay Kumar
你好! - karthik reddy

0
这是我创建的一个方法,你可以输入想要分组的关键字:
def group_sum(key,list_of_dicts):
    d = {}
    for dct in list_of_dicts:
        if dct[key] not in d:
            d[dct[key]] = {}
        for k,v in dct.items():
            if k != key:
                if k not in d[dct[key]]:
                    d[dct[key]][k] = v
                else:
                    d[dct[key]][k] += v
    final_list = []
    for k,v in d.items():
        temp_d = {key: k}
        for k2,v2 in v.items():
            temp_d[k2] = v2
        final_list.append(temp_d)
    return final_list


data = [
    {'name': 'A', 'tea':5, 'coffee':6},
    {'name': 'A', 'tea':2, 'coffee':3},
    {'name': 'B', 'tea':7, 'coffee':1},
    {'name': 'B', 'tea':9, 'coffee':4},
]

grouped_data = group_sum("name",data)
print (grouped_data)

结果:

[{'coffee': 5, 'name': 'B', 'tea': 16}, {'coffee': 9, 'name': 'A', 'tea': 7}]

我猜在对成千上万个字典进行求和时,与pandas相比会更慢,也许不是,我不知道。它似乎也不会保持顺序,除非你使用ordereddict或python 3.6。


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