2017-04-25 10 views
3

我有一個3D數組,只包含0,1和2的值,並且希望分別將這些值轉換爲0,128和255。我看了看周圍,這個線程(Translate every element in numpy array according to key)似乎是要走的路。Numpy:翻譯元素增加了很多文件大小(因子8)

所以我試着實現它,它的工作,代碼的相關部分可以看到下面(我讀寫數據和H5文件,但我懷疑這很重要,我只是提到它的情況下)

#fetch dataset from disk 
f = h5py.File('input/A.h5','r') #size = 572kB 

#read and transform array 
array = f['data'].value #type = numpy.ndarray 
my_dict = {1:128, 2:255, 0:0} 
array=np.vectorize(my_dict.get)(array) 

#write translated dataset to disk 
h5 = h5py.File('output/B.h5', driver=None) #final size = 4.5MB 
h5.create_dataset('data', data=array) 
h5.close() 

問題是,輸入文件(A.h5)的大小是572kB,輸出文件(B.h5)是8倍大(4.5MB)。

這是怎麼回事?我有另一個相同的數組,從0到255的值都是相同的,它的大小也是572kB,所以數字越大越好。我的第一個猜測是,也許python創建對象,而不是整數,我試圖鑄造爲int,但大小保持不變。

側面說明:如果我轉換數據與3縮進for循環,然後大小保持572KB(但代碼是慢得多)

+0

我懷疑在喜歡的問題中的另一個答案是更快,http://stackoverflow.com/a/29055933/901925。即使這樣你也會想看結果dtype。您也可以在create_dataset語句中指定dtype。 – hpaulj

回答

2

你可能會寫回你的陣列的Int64那裏獲得了8倍原始數組存儲爲uint8。你可以嘗試:

array=np.vectorize(my_dict.get)(array).astype(np.uint8) 

,然後保存到H5 ...

由於@Jaime所指出的,你告訴vectorize保存數組複製你想要的數據類型直客:

array=np.vectorize(my_dict.get, otypes=[np.uint8])(array) 
+0

謝謝,我實際上在將數組寫入磁盤後通過讀取它來檢查元素的數據類型,這是uint8,這就是爲什麼我不考慮這樣做。但是在加載數組後,可能會將其轉換回uint8,並且存儲爲int64 – Skum

+1

'np.vectorize(my_dict.get,otypes = [np.uint8])'將實現相同的目標併爲您節省數組副本,這就是'.astype()'結束了。 – Jaime

+1

謝謝@Jaime - 我在火車上急着寫了我的答案。我會在你的改進中編輯。 – xnx

1

雖然鏈接SO接受的答案使用np.vectorize,但它並不是最快的選擇,尤其是在這種情況下,您只需更換3個小數字0,1,2。

在SO問題的一個新的答案給出了一個簡單而快速索引替代:

https://stackoverflow.com/a/29055933/901925

In [508]: x=np.random.randint(0,3,(100,100,100)) 
In [509]: x.size 
Out[509]: 1000000 
In [510]: x1=np.vectorize(my_dict.get, otypes=['uint8'])(x) 
In [511]: arr=np.array([0,128,255],np.uint8) 
In [512]: x2=arr[x] 
In [513]: np.allclose(x1,x2) 
Out[513]: True 

比較它們的時間:

In [514]: timeit x1=np.vectorize(my_dict.get, otypes=['uint8'])(x) 
10 loops, best of 3: 161 ms per loop 
In [515]: timeit x2=arr[x] 
100 loops, best of 3: 3.48 ms per loop 

索引方法要快得多。

用戶經常會錯過的np.vectorize有幾件事。

  • 速度免責聲明;與明確的迭代相比,它不會保證顯着的速度。不過,它確實可以更輕鬆地迭代多維數組。

  • 沒有otypes,它從測試計算中確定返回數組的類型。有時候這種默認會導致問題在這裏指定otypes只是一個方便,馬上給你正確的dtype。

由於好奇心的問題,以下是名單的理解方式的時間:

In [518]: timeit x3=np.array([my_dict[i] for i in x.ravel()]).reshape(x.shape) 
1 loop, best of 3: 556 ms per loop 

h5py可以讓你保存數據集時指定dtype。當我以不同的方式保存數組時,請注意type

In [529]: h5.create_dataset('data1',data=x1, dtype=np.uint8) 
Out[529]: <HDF5 dataset "data1": shape (100, 100, 100), type "|u1"> 
In [530]: h5.create_dataset('data2',data=x1, dtype=np.uint16) 
Out[530]: <HDF5 dataset "data2": shape (100, 100, 100), type "<u2"> 
In [531]: h5.create_dataset('data3',data=x1) 
Out[531]: <HDF5 dataset "data3": shape (100, 100, 100), type "|u1"> 
In [532]: x.dtype 
Out[532]: dtype('int32') 
In [533]: h5.create_dataset('data4',data=x) 
Out[533]: <HDF5 dataset "data4": shape (100, 100, 100), type "<i4"> 
In [534]: h5.create_dataset('data5',data=x, dtype=np.uint8) 
Out[534]: <HDF5 dataset "data5": shape (100, 100, 100), type "|u1"> 

所以,即使你沒有指定你仍然可以有這種類型的保存它vectorizeuint8