如果bitarray 无法安装,Dot Product in Python without NumPy 中的一维解决方案可以与相同的嵌套理解 (https://stackoverflow.com/a/35241087/901925) 一起使用。这没有利用数据的 0/1 特性。所以基本上这是一个嵌套迭代的练习。
def dot1d(a,b):
return sum(x*y for x,y in zip(a,b))
def dot_2cmp(a):
return [[dot1d(r,c) for c in a] for r in a]
itertools.product可以用来遍历行列组合,但是结果是一维列表,然后需要进行分组(不过这一步很快):
def dot2d(a):
aa=[dot1d(x,y) for x,y in itertools.product(a,a)]
return [aa[i::len(a)] for i in range(len(a))]
测试:
a=[[1,0,1,0],[0,1,0,1],[0,0,1,1],[1,1,0,0]]
In [246]: dot2d(a)
Out[246]: [[2, 0, 1, 1], [0, 2, 1, 1], [1, 1, 2, 0], [1, 1, 0, 2]]
In [247]: dot_2cmp(a)
Out[247]: [[2, 0, 1, 1], [0, 2, 1, 1], [1, 1, 2, 0], [1, 1, 0, 2]]
In [248]: np.dot(np.array(a),np.array(a).T).tolist()
Out[248]: [[2, 0, 1, 1], [0, 2, 1, 1], [1, 1, 2, 0], [1, 1, 0, 2]]
在较大列表的计时中,两个列表操作花费相同的时间。数组版本,即使是输入/输出数组转换也快得多。
In [254]: b=np.random.randint(0,2,(100,100)).tolist()
In [255]: timeit np.dot(np.array(b),np.array(b).T).tolist()
100 loops, best of 3: 5.46 ms per loop
In [256]: timeit dot2d(b)
10 loops, best of 3: 177 ms per loop
In [257]: timeit dot_2cmp(b)
10 loops, best of 3: 177 ms per loop
结果是对称的,因此跳过重复计算可能是值得的。将它们映射回嵌套列表将比在numpy 中工作更多。
In [265]: timeit [[dot1d(r,c) for c in b[i:]] for i,r in enumerate(b)]
10 loops, best of 3: 90.1 ms per loop
就其价值而言,我认为这些解决方案中的任何一个都不比其他解决方案“更 Pythonic”。只要它是用清晰、可运行的 Python 编写的,它就是 Pythonic。