(資料科學學習手札63)利用pandas讀寫HDF5檔案

費弗裡發表於2019-07-05

一、簡介

  HDF5(Hierarchical Data Formal)是用於儲存大規模數值資料的較為理想的儲存格式,檔案字尾名為h5,儲存讀取速度非常快,且可在檔案內部按照明確的層次儲存資料,同一個HDF5可以看做一個高度整合的資料夾,其內部可存放不同型別的資料。在Python中操縱HDF5檔案的方式主要有兩種,一是利用pandas中內建的一系列HDF5檔案操作相關的方法來將pandas中的資料結構儲存在HDF5檔案中,二是利用h5py模組來完成從Python原生資料結構向HDF5格式的儲存,本文就將針對pandas中讀寫HDF5檔案的方法進行介紹。

 

二、利用pandas操縱HDF5檔案

2.1 寫出

  pandas中的HDFStore()用於生成管理HDF5檔案IO操作的物件,其主要引數如下:

  path:字元型輸入,用於指定h5檔案的名稱(不在當前工作目錄時需要帶上完整路徑資訊)

  mode:用於指定IO操作的模式,與Python內建的open()中的引數一致,預設為'a',即當指定檔案已存在時不影響原有資料寫入,指定檔案不存在時則新建檔案;'r',只讀模式;'w',建立新檔案(會覆蓋同名舊檔案);'r+',與'a'作用相似,但要求檔案必須已經存在;

  complevel:int型,用於控制h5檔案的壓縮水平,取值範圍在0-9之間,越大則檔案的壓縮程度越大,佔用的空間越小,但相對應的在讀取檔案時需要付出更多解壓縮的時間成本,預設為0,代表不壓縮

  下面我們建立一個HDF5 IO物件store:

import pandas as pd

store = pd.HDFStore('demo.h5')
'''檢視store型別'''
print(store)

  可以看到store物件屬於pandas的io類,通過上面的語句我們已經成功的初始化名為demo.h5的的檔案,本地也相應的出現瞭如下的檔案:

  接下來我們建立pandas中不同的兩種物件,並將它們共同儲存到store中,首先建立series物件:

import numpy as np

#建立一個series物件
s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
s

  接著我們建立一個dataframe物件:

#建立一個dataframe物件
df = pd.DataFrame(np.random.randn(8, 3),
                 columns=['A', 'B', 'C'])
df

  第一種方式利用鍵值對將不同的資料存入store物件中,這裡為了程式碼簡潔使用了元組賦值法:

store['s'],store['df'] = s,df

  第二種方式利用store物件的put()方法,其主要引數如下:

  key:指定h5檔案中待寫入資料的key

  value:指定與key對應的待寫入的資料

  format:字元型輸入,用於指定寫出的模式,'fixed'對應的模式速度快,但是不支援追加也不支援檢索;'table'對應的模式以表格的模式寫出,速度稍慢,但是支援直接通過store物件進行追加和表格查詢操作

  使用put()方法將資料存入store物件中:

 

store.put(key='s',value=s);store.put(key='df',value=df)

 

  既然是鍵值對的格式,那麼可以檢視store的items屬性(注意這裡store物件只有items和keys屬性,沒有values屬性):

store.items

  呼叫store物件中的資料直接用對應的鍵名來索引即可:

store['df']

  刪除store物件中指定資料的方法有兩種,一是使用remove()方法,傳入要刪除資料對應的鍵:

store.remove('s')
print(store.keys())

  二是使用Python中的關鍵詞del來刪除指定資料:

del store['s']
print(store.keys())

  列印出的結果都如下:

  這時若想將當前的store物件持久化到本地,只需要利用close()方法關閉store物件即可:

store.close()
'''檢視store連線狀況,False則代表已關閉'''
store.is_open

  這時本地的h5檔案也相應的儲存進store物件關閉前包含的檔案:

  除了通過定義一個確切的store物件的方式,還可以從pandas中的資料結構直接匯出到本地h5檔案中:

#建立新的資料框
df_ = pd.DataFrame(np.random.randn(5,5))
#匯出到已存在的h5檔案中,這裡需要指定key
df_.to_hdf(path_or_buf='demo.h5',key='df_')
#建立於本地demo.h5進行IO連線的store物件
store = pd.HDFStore('demo.h5')
#檢視指定h5物件中的所有鍵
print(store.keys())

2.2 讀入

  在pandas中讀入HDF5檔案的方式主要有兩種,一是通過上一節中類似的方式建立與本地h5檔案連線的IO物件,接著使用鍵索引或者store物件的get()方法傳入要提取資料的key來讀入指定資料:

store = pd.HDFStore('demo.h5')
'''方式1'''
df1 = store['df']
'''方式2'''
df2 = store.get('df')
df1 == df2

  可以看出這兩種方式都能順利讀取鍵對應的資料。

  第二種讀入h5格式檔案中資料的方法是pandas中的read_hdf(),其主要引數如下:

  path_or_buf:傳入指定h5檔案的名稱

  key:要提取資料的鍵

  需要注意的是利用read_hdf()讀取h5檔案時對應檔案不可以同時存在其他未關閉的IO物件,否則會報錯,如下例:

print(store.is_open)
df = pd.read_hdf('demo.h5',key='df')

  把IO物件關閉後再次提取:

store.close()
print(store.is_open)
df = pd.read_hdf('demo.h5',key='df')
df

 2.3 速度比較

  這一小節我們來測試一下對於儲存同樣資料的csv格式檔案、h5格式的檔案,在讀取速度上的差異情況:

  這裡我們首先建立一個非常大的資料框,由一億行x5列浮點型別的標準正態分佈隨機陣列成,接著分別用pandas中寫出HDF5和csv格式檔案的方式持久化儲存:

import pandas as pd
import numpy as np
import time

store = pd.HDFStore('store.h5')
#生成一個1億行,5列的標準正態分佈隨機數表
df = pd.DataFrame(np.random.rand(100000000,5))
start1 = time.clock()
store['df'] = df
store.close()
print(f'HDF5儲存用時{time.clock()-start1}秒')
start2 = time.clock()
df.to_csv('df.csv',index=False)
print(f'csv儲存用時{time.clock()-start2}秒')

  在寫出同樣大小的資料框上,HDF5比常規的csv快了將近50倍,而且兩者儲存後的檔案大小也存在很大差異:

  csv比HDF5多佔用將近一倍的空間,這還是在我們沒有開啟HDF5壓縮的情況下,接下來我們關閉所有IO連線,執行下面的程式碼來比較對上述兩個檔案中資料還原到資料框上兩者用時差異:

import pandas as pd
import time

start1 = time.clock()
store = pd.HDFStore('store.h5',mode='r')
df1 = store.get('df')
print(f'HDF5讀取用時{time.clock()-start1}秒')
start2 = time.clock()
df2 = pd.read_csv('df.csv')
print(f'csv讀取用時{time.clock()-start2}秒')

  HDF5用時僅為csv的1/13,因此在涉及到資料儲存特別是規模較大的資料時,HDF5是你不錯的選擇。

 

  以上就是本文的全部內容,如有筆誤望指出!

 

相關文章