【问题标题】:Performance of row vs column operations in NumPyNumPy 中行与列操作的性能
【发布时间】:2013-07-31 01:40:57
【问题描述】:

a few articles 表明 MATLAB 更喜欢列操作而不是行操作,并且取决于您布置数据的性​​能 can vary significantly。这显然是因为 MATLAB 使用 column-major 顺序来表示数组。

我记得读过 Python (NumPy) 使用 row-major 顺序。有了这个,我的问题是:

  1. 在使用 NumPy 时,可以期待类似的性能差异吗?
  2. 如果对上述问题的回答是肯定的,那么有哪些可以突出这种差异的示例

【问题讨论】:

  • 您可能想查看this。这是最近的一个例子,不同轴上的操作存在很大差异。虽然这很可能是一个错误。

标签: python numpy benchmarking row-major-order column-major-order


【解决方案1】:

与许多基准测试一样,这实际上取决于具体情况。确实,默认情况下,numpy 以 C 连续(行优先)顺序创建数组,因此,抽象地说,扫描列的操作应该比扫描行的操作更快。但是,数组的形状、ALU 的性能以及处理器上的底层缓存对细节有很大的影响。

例如,在我的 MacBook Pro 上,使用小整数或浮点数组,时间差不多,但小整数类型明显比浮点类型慢:

>>> x = numpy.ones((100, 100), dtype=numpy.uint8)
>>> %timeit x.sum(axis=0)
10000 loops, best of 3: 40.6 us per loop
>>> %timeit x.sum(axis=1)
10000 loops, best of 3: 36.1 us per loop

>>> x = numpy.ones((100, 100), dtype=numpy.float64)
>>> %timeit x.sum(axis=0)
10000 loops, best of 3: 28.8 us per loop
>>> %timeit x.sum(axis=1)
10000 loops, best of 3: 28.8 us per loop

使用更大的数组,绝对差异会变得更大,但至少在我的机器上,对于更大的数据类型来说仍然更小:

>>> x = numpy.ones((1000, 1000), dtype=numpy.uint8)
>>> %timeit x.sum(axis=0)
100 loops, best of 3: 2.36 ms per loop
>>> %timeit x.sum(axis=1)
1000 loops, best of 3: 1.9 ms per loop

>>> x = numpy.ones((1000, 1000), dtype=numpy.float64)
>>> %timeit x.sum(axis=0)
100 loops, best of 3: 2.04 ms per loop
>>> %timeit x.sum(axis=1)
1000 loops, best of 3: 1.89 ms per loop

您可以告诉 numpy 使用 numpy.asarraynumpy.onesnumpy.zeros 等的 order='F' 关键字参数创建一个 Fortran 连续(列主要)数组,或者通过使用转换现有数组numpy.asfortranarray。正如预期的那样,这种排序交换了行或列操作的效率:

in [10]: y = numpy.asfortranarray(x)
in [11]: %timeit y.sum(axis=0)
1000 loops, best of 3: 1.89 ms per loop
in [12]: %timeit y.sum(axis=1)
100 loops, best of 3: 2.01 ms per loop

【讨论】:

    【解决方案2】:
    In [38]: data = numpy.random.rand(10000,10000)
    
    In [39]: %timeit data.sum(axis=0)
    10 loops, best of 3: 86.1 ms per loop
    
    In [40]: %timeit data.sum(axis=1)
    10 loops, best of 3: 101 ms per loop
    

    【讨论】:

      【解决方案3】:

      我怀疑它会根据数据和操作而有所不同。

      简单的答案是使用相同的、真实世界的数据以及您计划使用的功能编写一些测试,然后使用cprofiletimeit 来比较速度,对于您的操作,取决于您如何构建数据。

      【讨论】:

        【解决方案4】:

        正如其他回复所指出的那样,使用 numpy 函数往往不会产生显着的性能差异,但是如果您正在执行某种手动索引(通常应该尽可能避免),它可能很重要。 下面是一个“玩具”示例来演示这种效果:

        import numpy as np
        from time import time
        
        n = 100
        m = n ** 2
        x = np.ones((m, m),  dtype="float64")
        
        
        def row(mat):
            out = 0
            for i in range(n):
                out += np.sum(mat[i, :])
            return out
        
        
        def col(mat):
            out = 0
            for i in range(n):
                out += np.sum(mat[:, i])
        
            return out
        
        
        p = 100
        t = time()
        for i in range(p):
            s = row(x)
        print(time()-t)
        
        
        t = time()
        for i in range(p):
            s = col(x)
        print(time()-t)
        

        对于 'row()' = 0.2618 秒

        对于 'col()' = 1.9261 秒

        我们可以看到循环遍历行要快得多。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-27
          • 2017-07-30
          • 1970-01-01
          • 2011-12-07
          • 2013-05-31
          • 1970-01-01
          相关资源
          最近更新 更多