【问题标题】:Pythonic way of calculating A x A' (without numpy)Pythonic 计算 A x A' 的方法(没有 numpy)
【发布时间】:2016-02-06 11:13:31
【问题描述】:

所以 A 是一个仅包含 0 和 1 的列表。在不使用 nympy 或 scipy 的情况下计算 A * A' 的最 Pythonic(也相当快)的方法是什么。

上面的 numpy 等价物是:

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

【问题讨论】:

  • 只写算法。如果您需要性能,请使用 numpy。除了作为一个实验(然后你可以写下你自己的想法)或作为家庭作业之外,你的问题没有多大意义。
  • 是的,我确实需要速度,但问题是大多数 OJ 不支持 numpy。我希望有一个类似于 zip() 和 itertools 的解决方案:\
  • 我刚刚在这里看到了一个用于一维列表,使用 sumzip - 这很简单,因为它只产生一个数字。
  • 什么是 OJ?如果性能很重要,为什么不能在需要的地方安装 numpy?

标签: python numpy matrix multidimensional-array matrix-multiplication


【解决方案1】:

由于您的数据是零和一,因此最好的非 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]

【讨论】:

  • 如果他不能安装numpy,他可以安装bitarray吗?那也是第三方编译包。
  • 你是对的,它也是第三方包。也许他可以安装它,在这种情况下,这将是一个很好的解决方案。 OP 确实只指定了 numpy 和 scify。
  • 我无法安装任何东西。无论如何感谢这个答案,我不知道位数组:)
【解决方案2】:

如果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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-16
    • 2020-08-24
    • 1970-01-01
    • 2016-06-27
    • 2019-05-30
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多