16

几篇文章表明 MATLAB 更喜欢列操作而不是行操作,并且根据您对数据的布局,性能可能会有很大差异。这显然是因为 MATLAB 使用优先顺序来表示数组。

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

  1. 在使用 NumPy 时,是否可以期待类似的性能差异?
  2. 如果上面的答案是肯定的,那么有哪些例子可以突出这种差异
4

4 回答 4

15

像许多基准一样,这实际上取决于具体情况。确实,默认情况下,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 使用order='F'关键字参数numpy.asarraynumpy.onesnumpy.zeros等创建一个 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
于 2013-07-30T20:11:10.390 回答
3
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
于 2013-07-30T19:37:56.880 回答
2

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

简单的答案是使用相同的、真实的、您计划使用的类型的数据以及您计划使用的功能编写一些测试,然后根据您的操作使用cprofile或比较速度timeit结构化你的数据。

于 2013-07-30T18:57:25.410 回答
1

正如其他回复指出的那样,使用 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)

对于“行()”= 0.2618 秒

对于 'col()' = 1.9261 秒

我们可以看到遍历行的速度要快得多。

于 2021-12-23T16:59:02.070 回答