2017-08-09 159 views
3

所以我使用np.load()加載一些文件,大小範圍在150MB到250MB之間。每個文件都包含一個包含5個子數組的數組。一些文件在一秒鐘之內被加載,而另外一些則需要5秒來加載,並且由於我有很多這些文件,他們需要相當長的一段時間來處理所有這些都是由於加載時間較慢。但是,我注意到,如果將文件分成5個較小的文件(每個文件1個子數組),那麼加載時間總是很容易在每5個文件一秒之內。np.load()對於較大的文件異常緩慢

這可能是什麼原因造成的?我怎麼能加快np.load()沒有將每個文件分割成更小的文件?

+0

你是如何測量運行時間的?也許分割文件允許它適合[頁面緩存](https://en.wikipedia.org/wiki/Page_cache),這使得加載速度更快? –

+0

我只是非常粗略地計算它,但加載所有的文件需要大約一分鐘後分裂他們,而分裂之前需要接近10分鐘。我懷疑它只是頁面緩存。 – drulludanni

+1

這些文件的格式是什麼,你如何調用'np.load'? – kazemakase

回答

2

問題的根源在於numpy中並沒有真正的子數組的概念。如果你把陣列到陣列numpy的不知道他們是數組

import numpy as np 

a1 = np.ones(2**17) 
a2 = np.arange(2**18) 
a3 = np.random.randn(2**19) 

a = np.array([a1, a2, a3]) 

print(a.dtype) # object 

考慮這個例子。相反,它將它們視爲通用的Python對象。這就是documentation of np.save不得不說的是:

allow_pickle:BOOL,可選

允許保存使用Python泡菜對象數組。 [...]默認值:True

那麼會發生什麼是子陣列由pickler處理,這是超效率的。顯然,當你單獨保存數組時,不會發生這種情況。現在它們被有效地存儲爲numpy數組。不幸的是,你不能簡單地設置allow_pickle=False,因爲它不會讓你存儲對象數組。

解決方案是使用np.savez來存儲多個陣列。這裏是上面的陣列的時間比較:

np.save('test.npy', a) 
%timeit np.load('test.npy') # 10 loops, best of 3: 40.4 ms per loop 

np.savez('test2.npz', a1, a2, a3) 
%timeit np.load('test2.npz') # 1000 loops, best of 3: 339 µs per loop 

你可以retrive陣列

x = np.load('test2.npz') 
a1 = x['arr_0'] 
a2 = x['arr_1'] 
# ... 

這可能是更好的數組作爲關鍵字參數傳遞給savez,這allaws你給他們的名字:

np.savez('test3.npz', a1=a1, a2=a2, timmy=a3) 
x = np.load('test3.npz') 
a1 = x['a1'] 
a2 = x['a2'] 
a3 = x['timmy'] 
+0

那麼,如果你要保存一個多維矩陣,例如形狀矩陣(1024,1024,1024,1024),如果不能有效地通過numpy做到這一點呢? (我可能會壓扁它,保存它,然後加載並切片到合適的尺寸,但有沒有更好的方法來實現它?) – drulludanni

+1

多維數組是沒有問題的。你可以簡單地用'np.save'保存它。請注意,'[arr1,arr2,arr3,arr4,arr5]'是**不是**多維數組 - 它是列表中的數組,當您觀察時可能導致性能問題 – kazemakase