列表中对的乘积之和

Posted

技术标签:

【中文标题】列表中对的乘积之和【英文标题】:Sum of products of pairs in a list 【发布时间】:2015-05-04 20:25:45 【问题描述】:

这是我遇到的问题。给定一个列表

xList = [9, 13, 10, 5, 3]

我想计算每个元素乘以后续元素的总和

sum([9*13, 9*10, 9*5 , 9*3]) + 
sum([13*10, 13*5, 13*3]) + 
sum([10*5, 10*3]) + 
sum ([5*3])

在这种情况下,答案是 608

有没有办法通过itertools 或本机使用numpy 来做到这一点?

下面是我想出的一个功能。它可以完成工作,但远非理想,因为我还想添加其他东西。

    def SumProduct(xList):
        ''' compute the sum of the product 
        of a list 
        e.g. 
        xList = [9, 13, 10, 5, 3]
        the result will be 
        sum([9*13, 9*10, 9*5 , 9*3]) + 
        sum([13*10, 13*5, 13*3]) + 
        sum([10*5, 10*3]) + 
        sum ([5*3])
        '''
        xSum = 0
        for xnr, x in enumerate(xList):
            #print xnr, x
            xList_1 = np.array(xList[xnr+1:])
            #print x * xList_1
            xSum = xSum + sum(x * xList_1)
        return xSum

任何帮助表示赞赏。

N.B:如果您想知道,我正在尝试使用 pandas

来实现 Krippendorf's alpha

【问题讨论】:

个人好奇心(查看文献),使用这种现实性比更流行的现实性有什么好处? 实际上,这种方法可以概括大多数其他方法,请参阅afhayes.com/public/cmm2007.pdf 和agreestat.com/book4 【参考方案1】:
x = array([9, 13, 10, 5, 3])
result = (x.sum()**2 - x.dot(x)) / 2

与其他可能具有二次性能的解决方案相比,这利用了一些数学简化来在线性时间和恒定空间中工作。

这是一个如何工作的图表。假设x = array([2, 3, 1])。那么,如果您将产品视为矩形区域:

x is this stick: -- --- -

x.sum()**2 is this rectangle:
   -- --- -
  |xx xxx x
  |xx xxx x

  |xx xxx x
  |xx xxx x
  |xx xxx x

  |xx xxx x

x.dot(x) is this diagonal bit:
   -- --- -
  |xx
  |xx

  |   xxx
  |   xxx
  |   xxx

  |       x

(x.sum()**2 - x.dot(x)) is the non-diagonal parts:
   -- --- -
  |   xxx x
  |   xxx x

  |xx     x
  |xx     x
  |xx     x

  |xx xxx

and (x.sum()**2 - x.dot(x)) / 2 is the product you want:
   -- --- -
  |   xxx x
  |   xxx x

  |       x
  |       x
  |       x

  |

【讨论】:

@WarrenWeckesser:哎呀。固定。 天哪。数学有时非常有用,对吧? 比 itertools 领先一英里,你能解释一下它是如何工作的吗? @PadraicCunningham:我尝试制作一些 ASCII 艺术图表。他们有帮助吗? 另一种方式来了解其工作原理:从总和的平方开始,例如 (a+b+c+d)^2。这扩展为具有一大堆术语(将其放入 WolframAlpha 中查看)。我们想要所有的项,除了那些只有元素平方的项,所以需要减去这些项。剩下的项都乘以 2,所以除以它,我们就得到了我们想要的。【参考方案2】:

您实际上想要组合而不是产品:

from itertools import combinations

print(sum(a*b for a,b in combinations(xList,2)))
608

即使是从 python 列表创建一个 numpy 数组,@user2357112 的答案也会和我们一起擦地板。

In [38]: timeit sum(a*b for a,b in combinations(xlist,2))
10000 loops, best of 3:
89.7 µs per loop

In [40]: timeit sum(mul(*t) for t in itertools.combinations(xlist, 2))
1000 loops, best of 3:
165 µs per loop

In [41]: %%timeit                                        
x = array(arr)
(x.sum()**2 - (x**2).sum()) / 2
   ....: 
100000 loops, best of 3:
 10.9 µs per loop

In [42]: timeit np.triu(np.outer(x, x), k=1).sum()
10000 loops, best of 3:
48.1 µs per loop
In [59]: %%timeit
....: xarr = np.array(xList)
....: N = xarr.size
....: range1 = np.arange(N)
....: mask = range1[:,None] < range1
....: out = ((mask*xarr)*xarr[:,None]).sum()
10000 loops, best of 3: 30.4 µs per loop

所有列表/数组都有 50 个元素。

从 user2357112 中窃取逻辑并将其用于 sum python 的普通列表非常有效:

In [63]: timeit result = (sum(xList)**2 - sum(x ** 2 for x in xList)) / 2
100000 loops, best of 3: 
4.63 µs per loop

但对于大型数组,numpy 解决方案仍然明显更快。

【讨论】:

【参考方案3】:

这是一种方法:

In [14]: x = [9, 13, 10, 5, 3]

In [15]: np.triu(np.outer(x, x), k=1).sum()
Out[15]: 608

但我会选择@user2357112 的回答。

【讨论】:

【参考方案4】:

您似乎想要获取该列表中两个元素(对)的每个组合,计算每对元素的乘积,并对这些乘积求和:

import itertools

xlist = [9, 13, 10, 5, 3]
pairs = itertools.combinations(xlist, 2)
answer = 0
for pair in pairs:
    answer += pair[0] * pair[1]

做到这一点的唯一方法:

import itertools
import operator

sum(operator.mul(*t) for t in itertools.combinations(xlist, 2))

【讨论】:

谢谢。 itertools.combinations 是我所缺乏的。我选择了 user2357112 答案,因为它更笼统地解释了这个问题。【参考方案5】:

如果您有兴趣手动执行此操作(无需标准库的帮助):

def combinations(L):
    for i,elem in enumerate(L):
        for e in L[i+1:]:
            yield (elem, e)

def main(xlist):
    answer = 0
    for a,b in combinations(xlist):
        answer += a*b
    return answer

【讨论】:

为什么不用标准库? 有时,人们对解决问题的算法感兴趣,而不是快速的单线。这正是为什么我都以“如果您有兴趣手动执行此操作”作为我的回答开头,并添加了a more pythonic answer 该问题明确要求使用itertoolsnumpy 提供解决方案。 @chepner:我已经添加了这样的答案。但是,即使 OP 不感兴趣,未来的用户可能仍然对此答案感兴趣。这正是我将此解决方案作为单独答案发布的原因 @chepner:嗯,“也许有”不足以排除其他答案,恕我直言。【参考方案6】:

一种方法 -

xarr = np.array(xList)

N = xarr.size
range1 = np.arange(N)

mask = range1[:,None] < range1
out = ((mask*xarr)*xarr[:,None]).sum()

另一个 -

xarr = np.array(xList)

N = xarr.size
range1 = np.arange(N)

R,C = np.where(range1[:,None] < range1)
out = (xarr[R]*xarr[C]).sum()

【讨论】:

以上是关于列表中对的乘积之和的主要内容,如果未能解决你的问题,请参考以下文章

在python中生成列表的条件乘积(组合)

如何找到列表中两个元素的最大乘积?

从Ruby中的列表中获取所有对的组合

如何使用python查找成对的卡片包列表

如何在 Python 中对元组列表列表进行平面映射? [复制]

我在 reducer 输出中得到一个列表列表,而不是成对的值,我不确定在我的代码中要更改啥