Python Numpy二维数组遍历效率对比:切片与Numba加速实测

陆遥
陆遥
发布时间:2026-10-15 | 5人浏览过
原创

本文通过实测对比Python中Numpy二维数组的两种遍历方式:双层循环与切片后一维遍历,并引入Numba JIT加速。结果显示,切片遍历通常更快,但Numba首次调用存在编译开销。文章详细解析了不同数据规模下的耗时差异及底层内存引用机制,为高性能计算提供实践参考。

Numpy二维数组遍历方式对比

在使用python-numpy处理数据时,访问数组元素主要有两种方式:一是使用双层for循环直接遍历所有元素,二是先对数组进行切片操作提取每一行,再对得到的一维数组进行遍历。

具体实现代码如下:

import numpy as np
import time
NUM = 160


a=np.random.random((NUM,NUM))
start = time.time()
for i in range(NUM):
    for j in range(NUM):
        if a[i][j] == 1.0:
            pass
end1 =  time.time()

for ii in range(NUM):
    b = a[ii,:]
    for jj in range(NUM):
        if b[jj] == 1.0:
            pass 
end2 =  time.time()
print("end1",end1-start)
print("end2",end2-end1)

由于生成的随机数位于[0,1)区间内,上述两种操作均会完整遍历数组中的所有元素。经过多轮测试,得到的耗时数据如下:

当数组规模NUM设置为160时:

end1 0.006983518600463867 end2 0.003988742828369141

当数组规模NUM扩大至1600时:

end1 0.71415114402771 end2 0.45178747177124023

结论:切片后的遍历方式速度更快。 原因分析: 作者目前尚未完全明确具体原因。

一种可能的解释:

b=a[ii,:]

在中,为了提高运行效率,切片生成的子矩阵实际上只是原矩阵的内存引用(视图),因此修改子矩阵会影响原矩阵。在内层循环中,第二种方法直接在元素所在的内存区域进行查找;而第一种方法需要先定位行索引,再定位列索引,涉及更多的寻址操作,因此速度较慢。欢迎分享其他观点。

Numba加速对性能的影响

关于numba在小数据量下性能反而低于普通操作的现象分析

什么是numba?

numba简介

实验对比:

import numpy as np
import time
NUM = 160
from numba import jit
a=np.random.random((NUM,NUM))

@jit(nopython=True)
def fun1(a):
    for i in range(NUM):
        for j in range(NUM):
            if a[i][j] == 1.0:
                pass

def fun2(a):
    for i in range(NUM):
        for j in range(NUM):
            if a[i][j] == 1.0:
                pass
    
@jit(nopython=True)
def fun3(a):
    for ii in range(NUM):
        b = a[ii,:]
        for jj in range(NUM):
            if b[jj] == 1.0:
                pass 


def fun4(a):
    for iii in range(NUM):
        b = a[iii,:]
        for jjj in range(NUM):
            if b[jjj] == 1.0:
                pass 

start = time.time()
fun1(a)
end1 =  time.time()
fun2(a)
end2 =  time.time()
fun3(a)
end3 =  time.time()
fun4(a)
end4 =  time.time()
print("end1",end1-start)
print("end2",end2-end1)
print("end3",end3-end2)
print("end4",end4-end3)

首先,当NUM为1600时,测试结果如下:

end1 0.2991981506347656 #无切片,有加速 end2 0.6372940540313721 #无切片,无加速 end3 0.08377814292907715 #有切片,有加速 end4 0.358079195022583 #有切片,无加速

在其他条件相同的情况下,使用切片的速度更快。同时,启用加速的效果也优于未加速的情况。 然而,当NUM设置为160时,结果如下:

end1 0.29620814323425293 #无切片,有加速 end2 0.006980180740356445 #无切片,无加速 end3 0.08580684661865234 #有切片,有加速 end4 0.0029993057250976562 #有切片,无加速

尽管有切片的情况依然比无切片快,但启用加速后的运行时间却比未加速时更长。 原因在于:@jit(nopython=True)装饰器仅对函数进行修饰,首次调用时会触发编译过程,将代码转换为机器码,这一过程需要消耗时间;后续调用则直接使用编译后的代码,速度显著提升。

实验相关代码如下:

import numpy as np
import time
NUM = 160
from numba import jit
a=np.random.random((NUM,NUM))

@jit(nopython=True)
def fun1(a):
    for i in range(NUM):
        for j in range(NUM):
            if a[i][j] == 1.0:
                pass

def fun2(a):
    for i in range(NUM):
        for j in range(NUM):
            if a[i][j] == 1.0:
                pass
    
@jit(nopython=True)
def fun3(a):
    for ii in range(NUM):
        b = a[ii,:]
        for jj in range(NUM):
            if b[jj] == 1.0:
                pass 


def fun4(a):
    for iii in range(NUM):
        b = a[iii,:]
        for jjj in range(NUM):
            if b[jjj] == 1.0:
                pass 

for b in range(4):
    start = time.time()
    fun1(a)
    end1 =  time.time()
    fun2(a)
    end2 =  time.time()
    fun3(a)
    end3 =  time.time()
    fun4(a)
    end4 =  time.time()
    print("end1",end1-start)
    print("end2",end2-end1)
    print("end3",end3-end2)
    print("end4",end4-end3)
    print("---")

运行结果如下:

end1 0.29421305656433105 end2 0.0059833526611328125 end3 0.08181905746459961 end4 0.0029909610748291016 --- end1 0.0 end2 0.005949735641479492 end3 0.0 end4 0.004008769989013672 --- end1 0.0 end2 0.006977558135986328 end3 0.0 end4 0.00399017333984375 --- end1 0.0 end2 0.005974292755126953 end3 0.0 end4 0.003837108612060547 ---

结论总结:

在使用numba加速时,第一次调用需要执行编译过程,因此耗时较长;之后的调用则无需重复编译,速度大幅提升。

至此,关于Python中Numpy二维数组遍历与切片后遍历效率比较的内容介绍完毕。如需了解更多相关Numpy二维数组遍历与二维数组切片后遍历效率比较的内容,请搜索本站历史文章或继续浏览下方相关文章。希望大家今后多多支持本站!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表