2017-08-11 46 views
4

我试图在Python中执行条件和积。简化的思路如下:基于行输入的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脚本。 有人能指点我正确的方向吗?

+0

你能澄清A和B之间的关系吗? – illiteratecoder

+0

当然,一些上下文: 我有公司名称(行),的Excel文件与** **列1 °“类型” =要施加 2°百分比= B 我需要得到各类公司的百分比总和。 希望这有助于!如果没有,请拍! –

+1

这种情况下的产品是什么?似乎你只是想要一笔钱 – illiteratecoder

回答

3

这似乎是一个很好的适合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] 

如果第三方包可能是你的选择,你也可以使用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包的作者。

+0

感谢您的好评! :) 还有一个问题,A中的值没有排序..可能是,例如: A = [1 1 1 2 3 2 1 4 2 1] B中的值与这些中的值匹配这些命令。所以如果我排序A,B不再匹配了吗? –

+0

在这种情况下,您可以对'zip'进行排序。而不是只使用'zip(A,B)',你必须使用'sorted(zip(A,B),key = lambda x:x [0])'(基于A排序而不丢失B的相应值) 。这只适用于'itertools.groupby' - 尽管'iteration_utilities.groupedby'不需要排序。 – MSeifert

+0

谢谢,完美无缺! :) 有没有为10个不同的B colums做这个选项?或者更好地运行该程序10次? –

0

我想你可以使用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的人数相等的彼此相邻。如果它们不是,你可能需要对它们进行排序或使用不同的算法。

2

我想出了这样的东西。有边缘情况下,我不知道该怎么做,并且希望可以将其删除:

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}) 

EDIT2:

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

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}) 
+2

你可以使用'defaultdict'初始化为0来避免'try - except'块 – KGS

+0

而不是使用'lambda: 0'只需使用'int'。这是因为'int()'(不带参数)返回'0' :) – MSeifert

+0

谢谢,现在看起来很愉快。 – gonczor

0

如果你不介意使用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])) 

此外,由于你有大名单,这真的可以加快运营速度

+0

只是为了完整:此答案中提到的方法*部分*基于此[答案](https://stackoverflow.com/a/45634302)。 – MSeifert