Python 基于行输入的条件总和

Conditional sum in Python based on row input

我正在尝试在 Python 中做条件和积。简化思路如下:

A = [1 1 2 3 3 3]
B = [0.50 0.25 0.99 0.80 0.70 0.20]

我想要输出

Total1 = 0.50*1 + 0.25*1
Total2 = 0.99*2
Total3 = 0.80*3 + 0.70*3 + 0.20*3

我正在考虑使用 FOR ... IF... 结构,指定对于 A 中的给定值,应将 B 中的所有对应值相加。

实际上这是一个巨大的数据集,所以我必须让脚本能够遍历所有类别?

此时此刻,我正在努力将想法转化为合适的 Python 脚本。 有人能给我指出正确的方向吗?

我想你可以使用 itertools.groupby:

来解决这个问题
import itertools
from operator import itemgetter

results = [group * sum(v[1] for v in values)
           for group, values in itertools.groupby(zip(A, B), itemgetter(0))]

这假设 A 中所有相同的数字彼此相邻。如果它们可能不是,您要么需要对它们进行排序,要么使用不同的算法。

这似乎非常适合 itertools.groupby(假设 A 中的值是 排序的 ,它可能无法正常工作 A=[1,1,2,2,1]):

from itertools import groupby
A = [1, 1, 2, 3, 3, 3]
B = [0.50, 0.25, 0.99, 0.80, 0.70, 0.20]

for key, grp in groupby(zip(A, B), key=lambda x: x[0]):
    grp = [i[1] for i in grp]
    print(key, key * sum(grp))

打印:

1 0.75
2 1.98
3 5.1

您也可以将其存储在列表中而不是打印值:

res = []
for key, grp in groupby(zip(A, B), key=lambda x: x[0]):
    grp = [i[1] for i in grp]
    res.append(key*sum(grp))
print(res)
# [0.75, 1.98, 5.1]

如果第 3 方包可能适合您,您也可以使用 iteration_utilities.groupedby:

>>> from iteration_utilities import groupedby
>>> from operator import itemgetter, add

>>> {key: key*sum(value) for key, value in groupedby(zip(A, B), key=itemgetter(0), keep=itemgetter(1)).items()}
{1: 0.75, 2: 1.98, 3: 5.1}

或者直接使用groupedbyreduce参数:

>>> groupedby(zip(A, B), key=itemgetter(0), keep=lambda x: x[0]*x[1], reduce=add)
{1: 0.75, 2: 1.98, 3: 5.1}

免责声明:我是 iteration_utilities 软件包的作者。

我想到了这样的事情。有边缘情况我不知道该怎么做,希望可以删除:

In [1]: sums = {}
In [2]: A = [1, 1, 2, 3, 3, 3]
   ...: B = [0.50, 0.25, 0.99, 0.80, 0.70, 0.20]
In [3]: for count, item in zip(A, B):
    ...:     try:
    ...:         sums[count] += item * count
    ...:     except KeyError:
    ...:         sums[count] = item * count
    ...:         

In [4]: sums
Out[5]: {1: 0.75, 2: 1.98, 3: 5.1}

编辑:

正如评论中所建议的那样 deafultdict 可以用来摆脱这个丑陋的 try-except 块:

In [2]: from collections import defaultdict

In [3]: sum = defaultdict(lambda: 0)

In [4]: sum[1]
Out[4]: 0

In [5]: sum
Out[5]: defaultdict(<function __main__.<lambda>>, {1: 0})

编辑 2:

嗯,我今天学到了一些东西。更多评论后:

In [6]: sums = defaultdict(int)

In [7]: A = [1, 1, 2, 3, 3, 3]
   ...: B = [0.50, 0.25, 0.99, 0.80, 0.70, 0.20]

In [8]: for count, item in zip(A, B):
   ...:     sums[count] += count * item
   ...:     

In [9]: sums
Out[9]: defaultdict(int, {1: 0.75, 2: 1.98, 3: 5.1})

如果您不介意为此使用 numpy 并假设这些组是有序的,您可以通过以下方式完成:

A = [1, 1, 2, 3, 3, 3]
B = [0.50, 0.25, 0.99, 0.80, 0.70, 0.20]
A = np.asarray([1, 1, 2, 3, 3, 3])
B = np.asarray([0.50, 0.25, 0.99, 0.80, 0.70, 0.20])
index = np.full(len(A),True)
index[:-1] = A[1:] != A[:-1]
prods = A*B

#result
res = np.add.reduceat(prods, np.append([0], (np.where(index)[0]+1)[:-1]))

此外,如果您有大型列表,这确实可以加快操作速度