为什么Numpy数组的迭代比直接操作快

ql3eal8s  于 2022-11-23  发布在  其他
关注(0)|答案(2)|浏览(143)

我想知道在数组的前两个维度上进行迭代是否比按列进行操作慢得多。令我惊讶的是,我发现按元素进行操作实际上更快。有人能解释一下吗?
代码如下:

def row_by_row(arr, cop):

    for i in range(arr.shape[0]):
        for ii in range(arr.shape[1]):
            arr[i, ii] = cop[i, ii].copy()

    return arr

def all(arr, cop):

    for i in range(arr.shape[1]):
        arr[:,i] = cop[:, i].copy()

    return arr

print(timeit.timeit("row_by_row(arr, cop)", setup="arr=np.ones((26, 15, 5000)); cop = np.random.random((26, 15,5000))",number=50, globals=globals()))
print(timeit.timeit("all(arr, cop)",setup="arr=np.ones((26, 15, 5000)); cop=np.random.random((26, 15,5000))",  number=50, globals=globals()))

这是一个时机:

0.12496590000000007
0.4989047
nhhxz33t

nhhxz33t1#

因为all通过迭代列而不是行,实际上缓存效率很低。
numpy数组中的数据按维度存储-行、列、第三维等。如果我们读取一行,它将是一个可以有效缓存的连续内存段。如果我们按列读取,它在这里是几个字节,跳过几KB,而不是读取更多的字节,等等-这会导致大量的缓存未命中。如果我们增加第三维,问题会变得更加明显。例如50 K。
按行而不是按列读取可消除差异:

def all_by_rows(arr, cop):
    for row in range(arr.shape[0]):
        arr[row, :] = cop[row, :].copy()
    return arr

timeit,具有50 k第三维:

1.249532633984927  # row_by_row - which is actually by third dimension
2.0826793879969046  # all
1.3391598959860858  # all_by_rows

没有不必要的.copy(),正如马可所指出的:

1.0241080590058118
0.9834478280099574
0.6739323509973474
cpjpxq1n

cpjpxq1n2#

简短答案:

内存配置

详细答案:

正如问题中的评论者所指出的,测量结果似乎非常不可靠。将测量的操作次数增加到2000次会得到更稳定的结果
行数:3.519135099995765
全部:5.321293300003163
有一点肯定会影响性能,那就是数组在内存中的存储方式以及缓存命中/未命中的数量。

def matrix(arr, cop):

    for i in range(arr.shape[0]):
        arr[i] = cop[i].copy()

    return arr

这在性能上比复制“列”稍好一些
矩阵:4.6333566999965115
但还是比一排一排的慢,为什么?
为此,让我们从循环中后退一步

def just_copy(arr, cop):
    return cop.copy()

副本:5.482903500000248
在复制整个过程中,我们又慢了!
我认为,循环数组更快的原因主要是内存分配,也可能是复制NumPy结构的额外开销。

相关问题