所以A是一个只包含0和1的列表。在不使用nympy或scipy的情况下计算A * A'的最pythonic(也是相当快)的方法是什么。
上面的numpy等价物是:
def foo(a):
return a * a.T
答案 0 :(得分:2)
由于你的数据是0和1,可能最好的非numpy解决方案是使用bitarrays:
def dot_self(matrix):
""" Multiply a 0-1 matrix by its transpose.
Use bitarrays to possibly speed up calculations.
"""
from bitarray import bitarray
rows = tuple(bitarray(row) for row in matrix)
return [[(r & c).count() for c in rows] for r in rows]
答案 1 :(得分:1)
如果无法安装bitarray
,Dot Product in Python without NumPy中的1d解决方案可以使用相同的嵌套式解析(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
可用于迭代行和列组合,但结果是1d列表,然后需要进行分组(但这一步很快):
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]]
在较大列表的时间中,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。