对值相同的列表进行求和和聚合

3 投票
3 回答
1574 浏览
提问于 2025-04-18 13:50

我有一对长度相同的列表,第一个列表里是整数,第二个列表里是浮点数。我想用另一对可能更短但仍然长度相同的列表来替换它们,新的第一个列表只包含唯一的值,而第二个列表则包含每个匹配值的总和。也就是说,如果新列表的第i个元素是 x,而原始列表的第一个列表中 x 出现的索引是 i_1,...,i_k,那么新列表的第二个列表的第i个元素应该包含原始列表第二个列表中索引 i_1,...,i_k 的值的总和。

举个例子会更清楚。

输入:

([1, 2, 2, 1, 1, 3], [0.1, 0.2, 0.3, 0.4, 0.5, 1.0])

输出:

([1, 2, 3], [1.0, 0.5, 1.0])

我试着用一些列表推导的技巧来实现这个,但没成功。我可以写一个简单的循环函数来完成这个,但我觉得应该有更好的方法。

3 个回答

1

创建一个包含以下键的地图:

la,lb = ([1, 2, 2, 1, 1, 3], [0.1, 0.2, 0.3, 0.4, 0.5, 1.0])
m = {k:0.0 for k in la}

然后用这些键的总和来填充它:

for i in xrange(len(lb)):
    m[la[i]] += lb[i]

最后,从你的地图中:

zip(*[(k,m[k]) for k in m]*1)
3

一种方法是使用 pandas 库:

>>> import pandas as pd
>>> df = pd.DataFrame({'tag':[1, 2, 2, 1, 1, 3], 
                       'val':[0.1, 0.2, 0.3, 0.4, 0.5, 1.0]})
>>> df
   tag  val
0    1  0.1
1    2  0.2
2    2  0.3
3    1  0.4
4    1  0.5
5    3  1.0
>>> df.groupby('tag')['val'].aggregate('sum')
tag
1      1.0
2      0.5
3      1.0
Name: val, dtype: float64
3

这不是一个一行代码的解决方案,但因为你没有分享你的解决办法,我来建议一个使用 collections.OrderedDict 的方法:

>>> from collections import OrderedDict
>>> a, b = ([1, 2, 2, 1, 1, 3], [0.1, 0.2, 0.3, 0.4, 0.5, 1.0])
>>> d = OrderedDict()
>>> for k, v in zip(a, b):
...     d[k] = d.get(k, 0) + v
...     
>>> d.keys(), d.values()
([1, 2, 3], [1.0, 0.5, 1.0])

当然,如果顺序不重要的话,使用 collections.defaultdict 会更好:

>>> from collections import defaultdict
>>> a, b = ([1, 'foo', 'foo', 1, 1, 3], [0.1, 0.2, 0.3, 0.4, 0.5, 1.0])
>>> d = defaultdict(int)
>>> for k, v in zip(a, b):
    d[k] +=  + v
...     
>>> d.keys(), d.values()
([3, 1, 'foo'], [1.0, 1.0, 0.5])

撰写回答