2013-03-12 201 views
4

現在我有一個python程序構建一個相當大的2D numpy數組,並使用numpy.savetxt將它保存爲製表符分隔的文本文件。 numpy數組只包含浮點數。然後我在單獨的C++程序中一次讀取一行中的文件。python - 將numpy數組保存到一個文件(儘可能小的尺寸)

我想要做的是找到一種方法來完成相同的任務,儘可能少地改變我的代碼,這樣我就可以減少我在兩個程序之間傳遞的文件的大小。

我發現我可以使用numpy.savetxt保存到壓縮的.gz文件而不是文本文件。這將文件大小從〜2MB降低到〜100kB。

有沒有更好的方法來做到這一點?也許,我可能會將二進制numpy數組寫入文件以節省空間?如果是這樣,我該怎麼做,以便我仍然可以將它讀入C++程序?

謝謝你的幫助。我很感激我能得到的任何指導。

編輯:

有很多零的(在numpy的數組中的值的大概70%是0.0000),我不知道我怎麼能以某種方式利用這雖然併產生一個微小的文件我的C++程序可以在

+0

只是一個想法 - 你必須寫出來嗎?如果程序正在同時運行(或可以併發運行),則可以使用各種方法將數據從一個流式傳輸到另一個:命名管道,TCP套接字,共享內存等。 – 2013-03-12 20:59:40

回答

3

由於您有很多零,您只能寫出窗體(索引,數字)中的非零元素。

假設你用少量的非零數字數組:

In [5]: a = np.zeros((10, 10)) 

In [6]: a 
Out[6]: 
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]]) 

In [7]: a[3,1] = 2.0 

In [8]: a[7,4] = 17.0 

In [9]: a[9,0] = 1.5 

首先,隔離有趣的數字,它們的指標:

In [11]: x, y = a.nonzero() 

In [12]: zip(x,y) 
Out[12]: [(3, 1), (7, 4), (9, 0)] 

In [13]: nonzero = zip(x,y) 

現在您只需少量的數據元素離開了。最簡單的方法是將它們寫入文本文件:

​​

這也給你一個機會來觀察數據。在您的C++程序中,您可以使用fscanf來讀取此數據。

但是你可以更用struct寫入二進制數據減少大小:

In [17]: import struct 

In [19]: c = struct.Struct('=IId') 

In [20]: with open('numbers.bin', 'w+') as outf: 
    ....:  for r, k in nonzero: 
    ....:   outf.write(c.pack(r, k, a[r,k])) 

Struct構造函數的參數的裝置;使用本機日期格式'='。第一個和第二個數據元素是無符號整數'I',第三個元素是雙「d」。

在你的C++程序中,這個數據可能是最好的二進制數據讀入打包的struct

編輯:答案更新爲二維數組。

+0

儘管數組是二維的,但仍然可以使用單個索引通過考慮平面數組來引用非零元素。 – Dave 2013-03-12 21:07:31

+0

我完全忽略了它是一個二維數組。哎呀。 – 2013-03-12 21:08:39

+0

有沒有辦法調整代碼給我兩個指數(因爲它是一個二維數組)。或者是增加另一個循環的唯一途徑? 謝謝你非常透徹的答覆。 – user1764386 2013-03-12 21:19:01

0

如果您不介意安裝其他軟件包(對於pythonc++),您可以使用[BSON][1](二進制JSON)。

+1

BSON文件爲,甚至根據作者說,很少比等效的JSON文件小。它有其優點,但節省空間不在其中。 – delnan 2013-03-12 19:31:13

+0

感謝,很高興知道 – shx2 2013-03-12 19:32:21

1

numpy.ndarray.tofilenumpy.fromfile對於python的直接二進制輸出/輸入非常有用。 std::ostream::writestd::istream::read對於C++中的二進制輸出/輸入非常有用。

如果數據從一臺機器傳輸到另一臺機器,您應該小心。

+0

你能解釋一下如何讀取在C++中使用'ndarray.tofile'編寫的文件嗎? – shx2 2013-03-12 19:30:51

+0

當使用ndarray.tofile()時,生成的文件實際上比使用numpy.savetxt時略大。我可能錯過了一個論點來告訴它輸出純二進制文件嗎? – user1764386 2013-03-12 19:38:08

+0

Endianness:http://stackoverflow.com/questions/13672597/numpys-tostring-fromstring-what-do-i-need-to-specify-to-restore-the-array – 2013-03-12 19:41:20

3

除非您確定不需要擔心字節順序等問題,否則最好使用numpy.savez,正如@ unutbu的回答和@ jorgeca的評論所述:numpy's tostring/fromstring --- what do I need to specify to restore the array

如果生成的大小不夠小,總會有zlib(在python的端:import zlib,在C++端,我相信一個實現存在)。

另一種方法是使用hdf5格式:雖然它不一定會減小磁盤上的文件大小,但它確實可以更快地節省/加載(這是格式設計的大數據陣列)。有hdf5的Python和C++讀者/作者。

+0

我似乎在這裏誤解了一些東西。使用numpy.savez可以保存我的數組的zip文件,但它不會被壓縮,因此不會變小。 這樣做是否有優勢,而不是在numpy.savetxt中指定.gz擴展名(將文件壓縮到〜100kB)? 我非常感謝幫助。 – user1764386 2013-03-12 19:50:43

+0

save/savez的優點主要在於便攜性。如果您確定只會將文件加載到保存的相同體系結構中,則可能不需要打擾這些文件。儘管如此,'hdf5'仍然是一個更好的選擇 - 除非你所做的不是一次性的一次性計時器。 – 2013-03-12 19:58:37

1

使用hdf5文件,它們通過h5py非常簡單,並且可以使用set compression標誌。請注意,hdf5也有一個C++接口。

相關問題