首頁 > 軟體

python中的Numpy二維陣列遍歷與二維陣列切片後遍歷效率比較

2022-03-01 13:01:35

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,:]

在numpy中,為了提高效率,這種切片出來的子矩陣其實都是原矩陣的參照而已,所以改變子矩陣,原矩陣還是會變的
所以在內層迴圈中,第二種方法是在那一行元素所在的記憶體進行尋找。而第一種方法是先定位到行,再定位到列,所以比較慢?
大家是怎麼想的呢?

關於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   #有切片,無加速

其他條件相同的情況下,有切片的速度更快。同樣,有numba加速的也比沒加速的快。
但當NUM =160時,結果如下:

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

有切片依舊比無切片的快。但是有numba加速的卻比沒有numba加速的慢。
原來@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二維陣列遍歷與二維陣列切片後遍歷效率比較內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com