NumPy中行与列操作的性能

Ame*_*ina 11 python benchmarking numpy

一些文章表明MATLAB比列操作更喜欢列操作,而且根据您布置数据的不同,性能会有很大差异.这显然是因为MATLAB使用列主要顺序来表示数组.

我记得读过Python(NumPy)使用行主要顺序.有了这个,我的问题是:

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

lmj*_*ns3 11

像许多基准一样,这实际上取决于具体情况.确实,默认情况下,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
Run Code Online (Sandbox Code Playgroud)

对于较大的阵列,绝对差异会变大,但对于较大的数据类型,至少在我的机器上仍然较小:

>>> 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
Run Code Online (Sandbox Code Playgroud)

你能告诉numpy的使用来创建一个Fortran连续(以列为主)阵列order='F'关键字参数numpy.asarray,numpy.ones,numpy.zeros,和类似物,或通过使用转换现有阵列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
Run Code Online (Sandbox Code Playgroud)


bas*_*man 5

正如其他回复指出的那样,使用 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)
Run Code Online (Sandbox Code Playgroud)

对于 'row()' = 0.2618 秒

对于 'col()' = 1.9261 秒

我们可以看到循环行的速度要快得多。