计算列表内成对点积的Pythonic方法

计算列表内成对点积的Pythonic方法,python,for-loop,Python,For Loop,我有一个由所有元组组合组成的列表,每个元素只能是-1或1。该列表可以生成为: N=2 list0 = [p for p in itertools.product([-1, 1], repeat=N)] 例如,如果元组具有N=2元素: 列表0=[(-1,-1),(-1,1),(1,-1),(1,1)] 因此,元组的总数是2^2=4 如果元组有N=3个元素: 列表0=[(-1,-1,-1),(-1,-1,1),(-1,1,-1),(-1,1,1), (1,-1,-1),(1,-1,1),(1,1,

我有一个由所有元组组合组成的列表,每个元素只能是-1或1。该列表可以生成为:

N=2
list0 = [p for p in itertools.product([-1, 1], repeat=N)]
例如,如果元组具有
N=2
元素:

列表0=[(-1,-1),(-1,1),(1,-1),(1,1)]

因此,元组的总数是
2^2=4

如果元组有
N=3个
元素:

列表0=[(-1,-1,-1),(-1,-1,1),(-1,1,-1),(-1,1,1), (1,-1,-1),(1,-1,1),(1,1,-1),(1,1,1)]

我关注的是:

现在我想得到列表中任意一对元组之间的点积的所有结果(包括元组本身的点积)。因此对于
N=2
将有
6(对)+4(本身)=10个组合对于
N=3
将有
28(对)+8(本身)=36个组合。

对于小型
N
我可以执行以下操作:

for x in list0:
    for y in list0:
        print(np.dot(x,y)) 

但是,假设我已经有了列表0,那么计算所有点积可能性的最佳方法是什么,如果N很大,比如~50?

你可以使用numpy

import numpy as np
import random


vals = []
num_vecs = 3
dimension = 4
for n in range(num_vecs):
    val = []
    for _ in range(dimension):
        val.append(random.random())
    vals.append(val)

# make into numpy array
vals = np.stack(vals)
print(vals.shape == (num_vecs, dimension))

# multiply every vector with every other using broadcastin
every_with_every_mult = vals[:, None] * vals[None, :]
print(every_with_every_mult.shape == (num_vecs, num_vecs, dimension))

# sum the final dimension
every_with_every_dot = np.sum(every_with_every_mult, axis=every_with_every_mult.ndim - 1)
print(every_with_every_dot.shape == (num_vecs, num_vecs))

# check it works
for i in range(num_vecs):
    for j in range(num_vecs):
        assert every_with_every_dot[i,j] == np.sum(vals[i]*vals[j])

您可以使用
np.dot
本身:

import numpy as np

list0 = [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (-1, 1, 1), (1, -1, -1), (1, -1, 1), (1, 1, -1), (1, 1, 1)]

# approach using np.dot
a = np.array(list0)
result = np.dot(a, a.T)

# brute force approach
brute = []
for x in list0:
    brute.append([np.dot(x, y) for y in list0])
brute = np.array(brute)

print((brute == result).all())
输出

True
True
您要问的是
a
与自身的矩阵乘法,来自:

如果a和b都是二维数组,则是矩阵乘法

请注意,最适合的解决方案是使用运算符
@

import numpy as np

list0 = [(-1, -1, -1), (-1, -1, 1), (-1, 1, -1), (-1, 1, 1), (1, -1, -1), (1, -1, 1), (1, 1, -1), (1, 1, 1)]

# approach using np.dot
a = np.array(list0)
result = a @ a.T

# brute force approach
brute = []
for x in list0:
    brute.append([np.dot(x, y) for y in list0])
brute = np.array(brute)

print((brute == result).all())
输出

True
True

注意:代码是在Python3.5中运行的

可能与@Bazingaano重复,问题是如何生成列表。我的问题是如何计算所有的点积efficiently@James事实上,简单地获取所有组合并调用
np.dot
的主要区别在于,对于一半的组合,结果将为零。谢谢,丹尼尔。然而,我认为这仍然是野蛮的力量。它与两个for循环有何不同?@James点函数是用优化的C/C++实现的,而两个
for
循环是用Python实现的。如果你想得到所有的点积,我相信你必须计算所有的点积,我认为最终结果的范围是固定的[-N,N]。所以我们可以建立一个哈希表/数组来存储所有结果的计数,就像直方图一样。那么你想要可能的值还是实际值?我想要实际值。可能的值肯定在[-N,N]范围内。对于实际值,我们只需要计算一个特定结果在所有可能结果中出现的次数。