如何对列表中由其他列分组的列求和?

Posted

技术标签:

【中文标题】如何对列表中由其他列分组的列求和?【英文标题】:How to sum a column grouped by other columns in a list? 【发布时间】:2018-09-07 05:55:01 【问题描述】:

我有一个清单如下。

[['Andrew', '1', '9'], ['Peter', '1', '10'], ['Andrew', '1', '8'], ['Peter', '1', '11'], ['Sam', '4', '9'], ['Andrew', '2', '2']]

我想总结最后一列按其他列分组。结果是这样的

[['Andrew', '1', '17'], ['Peter', '1', '21'], ['Sam', '4', '9'], ['Andrew', '2', '2']]

这仍然是一个列表。

在实际实践中,我总是想总结由许多其他列分组的最后一列。有没有办法在 Python 中做到这一点?非常感谢。

【问题讨论】:

【参考方案1】:

按除最后一列之外的所有列动态分组:

In [24]: df = pd.DataFrame(data)

In [25]: df.groupby(df.columns[:-1].tolist(), as_index=False).agg(lambda x: x.astype(int).sum()).values.tolist()
Out[25]: [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]

【讨论】:

[0,1]代表第一列和第二列吗? @Deepleeqe,是的,我还添加了另一个版本,它可以为任意数量的列动态完成...【参考方案2】:

这是通过collections.defaultdict 实现的 O(n) 解决方案,适用于任意数量的键。

如果您想要的输出是一个列表,那么这可能比通过 Pandas 的解决方案更可取,后者需要转换为非标准类型。

from collections import defaultdict

lst = [['Andrew', '1', '9'], ['Peter', '1', '10'], ['Andrew', '1', '8'],
       ['Peter', '1', '11'], ['Sam', '4', '9'], ['Andrew', '2', '2']]

d = defaultdict(int)

for *keys, val in lst:
    d[tuple(keys)] += int(val)

res = [[*k, v] for k, v in sorted(d.items())]

结果

[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]

说明

循环浏览您的列表,定义键/值并添加到您的defaultdict 列表中。 使用列表推导将字典转换为所需的输出。

【讨论】:

【参考方案3】:

Op1

您可以传递一个索引sum 并添加到列表转换回列表

pd.DataFrame(L).\
   set_index([0,1])[2].astype(int).sum(level=[0,1]).\
        reset_index().values.tolist()
Out[78]: [['Andrew', '1', 17], ['Peter', '1', 21], ['Sam', '4', 9], ['Andrew', '2', 2]]

Op2

对于列表列表,您可以使用来自itertoolsgroupby

from itertools import groupby
[k+[sum(int(v) for _,_, v in g)] for k, g in groupby(sorted(l), key = lambda x: [x[0],x[1]])]
Out[98]: [['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]

【讨论】:

【参考方案4】:

创建为DataFrame并聚合第三列由第一列和第二列转换为整数,最后转换回lists:

df = pd.DataFrame(L)
L = df[2].astype(int).groupby([df[0], df[1]]).sum().reset_index().values.tolist()
print (L)
[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]

以及defaultdict 的解决方案,仅限 python 3.x:

from collections import defaultdict

d = defaultdict(int)
#https://***.com/a/10532492
for *head, tail in L:
    d[tuple(head)] += int(tail)

d = [[*i, j] for i, j in sorted(d.items())]
print (d)
[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]

【讨论】:

【参考方案5】:

pd.factorizenp.bincount

f, u = pd.factorize([tuple(x[:-1]) for x in data])
v = np.array([x[-1] for x in data], int)

[list(k) + [int(v)] for k, v in zip(u, np.bincount(f, v))]

[['Andrew', '1', 17], ['Peter', '1', 21], ['Sam', '4', 9], ['Andrew', '2', 2]]

【讨论】:

【参考方案6】:

加了我的 2 美分。这两个都使用groupbyagg

V1:引入了新的求和函数。

sum=lambda x: x.astype(int).sum()
print(df.groupby([0,1], as_index=False).agg(2: sum).values.tolist())

V2:将列转换为数字

df[2] = pd.to_numeric(df[2])
print(df.groupby([0,1], as_index=False).agg(2: sum).values.tolist())

并且会返回:

[['Andrew', '1', 17], ['Andrew', '2', 2], ['Peter', '1', 21], ['Sam', '4', 9]]

【讨论】:

以上是关于如何对列表中由其他列分组的列求和?的主要内容,如果未能解决你的问题,请参考以下文章

如何对视图中的列进行求和/分组/排序

如何通过为每个单独的列列出分组后的所有数据并求和

在 CTE 中对日期范围内的列求和?

基于其他列的列的SQL总和[关闭]

将满足其他几个列条件的列组合在一起

根据 r 中的其他列对一个列表中的一列的所有值进行分组