
在使用python進行數據分析時,Jupyter Notebook是一個非常強力的工具,在數據集不是很大的情況下,我們可以使用pandas輕鬆對txt或csv等純文本格式數據進行讀寫。
然而當數據集的維度或者體積很大時,將數據保存並載入回內存的過程就會變慢,並且每次啟動Jupyter Notebook時都需要等待一段時間直到數據重新載入, 這樣csv格式或任何其他純文本格式數據都失去了吸引力。
本文將對pandas支持的多種格式數據在處理數據的不同方面進行比較,包含I/O速度、內存消耗、磁碟佔用空間等指標,試圖找出如何為我們的數據找到一個合適的格式的辦法!
——格式說明
現在對本文進行對比的幾種數據格式進行說明。
- CSV:最常用的數據格式
- Pickle:用於序列化和反序列化Python對象結構
- MessagePack:類似於json,但是更小更塊
- HDF5:一種常見的跨平台數據儲存文件
- Feather:一個快速、輕量級的存儲框架
- Parquet:Apache Hadoop的列式存儲格式
——指標說明
為了找到格式來存儲數據,本文選擇以下指標進行對比。
- size_mb:帶有序列化數據幀的文件的大小
- save_time:將數據幀保存到磁碟所需的時間
- load_time:將先前轉儲的數據幀載入到內存所需的時間
- save_ram_delta_mb:在數據幀保存過程中最大的內存消耗增長
- load_ram_delta_mb:數據幀載入過程中最大的內存消耗增長
注意,當我們使用有效壓縮的二進位數據格式(例如Parquet)時,最後兩個指標變得非常重要。它們可以幫助我們估算載入串列化數據所需的RAM數量,以及數據大小本身。我們將在下一部分中更詳細地討論這個問題。
——對比
現在開始對前文介紹的5種數據格式進行比較,為了更好地控制序列化的數據結構和屬性我們將使用自己生成的數據集。
下面是生成測試數據的代碼,我們隨機生成具有數字和分類特徵的數據集。數值特徵取自標準正態分布。分類特徵以基數為C的uuid4隨機字元串生成,其中2 <= C <= max_cat_size。
def generate_dataset(n_rows, num_count, cat_count, max_nan=0.1, max_cat_size=100):
dataset, types = {}, {}
def generate_categories():
from uuid import uuid4
category_size = np.random.randint(2, max_cat_size)
return [str(uuid4()) for _ in range(category_size)]
for col in range(num_count):
name = f'n{col}'
values = np.random.normal(0, 1, n_rows)
nan_cnt = np.random.randint(1, int(max_nan*n_rows))
index = np.random.choice(n_rows, nan_cnt, replace=False)
values[index] = np.nan
dataset[name] = values
types[name] = 'float32'
for col in range(cat_count):
name = f'c{col}'
cats = generate_categories()
values = np.array(np.random.choice(cats, n_rows, replace=True), dtype=object)
nan_cnt = np.random.randint(1, int(max_nan*n_rows))
index = np.random.choice(n_rows, nan_cnt, replace=False)
values[index] = np.nan
dataset[name] = values
types[name] = 'object'
return pd.DataFrame(dataset), types現在我們以CSV文件保存和載入的性能作為基準。將五個隨機生成的具有百萬個觀測值的數據集轉儲到CSV中,然後讀回內存以獲取平均指標。並且針對具有相同行數的20個隨機生成的數據集測試了每種二進位格式。
同時使用兩種方法進行對比:
- 1.將生成的分類變數保留為字元串
- 2.在執行任何I/O之前將其轉換為pandas.Categorical數據類型
1.以字元串作為分類特徵
下圖顯示了每種數據格式的平均I/O時間。這裡有趣的發現是hdf的載入速度比csv更低,而其他二進位格式的性能明顯更好,而feather和parquet則表現的非常好

保存數據並從磁碟讀取數據時的內存消耗如何?下一張圖片向我們展示了hdf的性能再次不那麼好。但可以肯定的是,csv不需要太多額外的內存來保存/載入純文本字元串,而feather和parquet則非常接近

最後,讓我們看一下文件大小的對比。這次parquet顯示出非常好的結果,考慮到這種格式是為有效存儲大量數據而開發的,也是理所當然

2.對特徵進行轉換
在上一節中,我們沒有嘗試有效地存儲分類特徵,而是使用純字元串,接下來我們使用專用的pandas.Categorical類型再次進行比較。

從上圖可以看到,與純文本csv相比,所有二進位格式都可以顯示其真強大功能,效率遠超過csv,因此我們將其刪除以更清楚地看到各種二進位格式之間的差異。

可以看到feather和pickle擁有最快的I/O速度,接下來該比較數據載入過程中的內存消耗了。下面的條形圖顯示了我們之前提到的有關parquet格式的情況

為什麼parquet內存消耗這麼高?因為只要在磁碟上佔用一點空間,就需要額外的資源才能將數據解壓縮回數據幀。即使文件在持久性存儲磁碟上需要適度的容量,也可能無法將其載入到內存中。
最後我們看下不同格式的文件大小比較。所有格式都顯示出良好的效果,除了hdf仍然需要比其他格式更多的空間。

結論
正如我們的上面的測試結果所示,feather格式似乎是在多個Jupyter之間存儲數據的理想選擇。它顯示出很高的I/O速度,不佔用磁碟上過多的內存,並且在裝回RAM時不需要任何拆包。
當然這種比較並不意味著我們應該在每種情況下都使用這種格式。例如,不希望將feather格式用作長期文件存儲。此外,當其他格式發揮最佳效果時,它並未考慮所有可能的情況。所以我們也需要根據具體情況進行選擇!
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/294704.html
微信掃一掃
支付寶掃一掃