计算 A x A' 的 Pythonic 方式(没有 numpy)

Pythonic way of calculating A x A' (without numpy)

所以 A 是一个仅包含 0 和 1 的列表列表。在不使用 nympy 或 scipy.

的情况下计算 A * A' 的最pythonic(并且也相当快)的方法是什么

上面的 numpy 等价物是:

def foo(a):
    return a * a.T

由于您的数据是零和一,最好的非 numpy 解决方案可能是使用位数组:

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]

如果bitarray无法安装, can be used with the same nested comprehension (中第1d的解决方法。这没有利用数据的 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]]

在较大列表的计时中,2 个列表操作花费相同的时间。数组版本,即使使用 in/out 数组转换也相当快。

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

就其价值而言,我认为这些解决方案中的任何一个都不如其他解决方案 'more Pythonic'。只要写明了,运行,Python就是Pythonic。