別再用CSV了,更高效的Python文件存儲方案

CSV無可厚非的是一種良好的通用文件存儲方式,幾乎任何一款工具或者編程語言都能對其進行讀寫,可是當文件特別大的時候,CSV這種存儲方式就會變得十分緩慢且低效。本文將介紹幾種在Python中可以代替CSV這種格式的其餘文件格式,並對比每種文件存儲的時間與大小。python

先說結論,parquet是最好的文件存儲格式,具體對比見下文。編程

生成隨機數據

導入依賴

import random
import string
import pickle
# 如下須要自行安裝
import numpy as np
import pandas as pd
import tables
import pyarrow as pa
import pyarrow.feather as feather
import pyarrow.parquet as pq

生成隨機數據

這裏使用pandas的dataframe來存儲數據dom

# 變量定義
row_num = int(1e7)
col_num = 5
str_len = 4
str_nunique = 10 # 字符串組合數量
# 生成隨機數
int_matrix = np.random.randint(0, 100, size=(row_num, col_num))
df = pd.DataFrame(int_matrix, columns=['int_%d' % i for i in range(col_num)])
float_matrix = np.random.rand(row_num, col_num)
df = pd.concat(
    (df, pd.DataFrame(float_matrix, columns=['float_%d' % i for i in range(col_num)])), axis=1)
str_list = [''.join(random.sample(string.ascii_letters, str_len))
            for _ in range(str_nunique)]
for i in range(col_num):
    sr = pd.Series(str_list*(row_num//str_nunique)
                   ).sample(frac=1, random_state=i)
    df['str_%d' % i] = sr

print(df.info())

生成100w行數據,其中整型,浮點型和字符串各5列,數據大小在內存裏大概爲1GB+編程語言

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000000 entries, 0 to 9999999
Data columns (total 15 columns):
 #   Column   Dtype  
---  ------   -----  
 0   int_0    int64  
 1   int_1    int64  
 2   int_2    int64  
 3   int_3    int64  
 4   int_4    int64  
 5   float_0  float64
 6   float_1  float64
 7   float_2  float64
 8   float_3  float64
 9   float_4  float64
 10  str_0    object 
 11  str_1    object 
 12  str_2    object 
 13  str_3    object 
 14  str_4    object 
dtypes: float64(5), int64(5), object(5)
memory usage: 1.1+ GB

保存文件

csv

CSV的保存方式很簡單,直接使用pandas自帶的to_csv() 方法便可工具

# 寫入
df.to_csv('./df_csv.csv', index=False)
# 讀取
df = pd.read_csv('./df_csv.csv')

寫入時間花費:78 s性能

讀取時間花費:11.8 sui

所需存儲空間:1.3GB設計

pkl

pkl文件須要用到built-inpicklecode

# 寫入
with open('./df_pkl.pkl', 'wb') as f:
    pickle.dump(df, f)
# 讀取
with open('./df_pkl.pkl', 'rb') as f:
    df = pickle.load(f)

寫入時間花費:2.89 s對象

讀取時間花費:2.61 s

所需存儲空間:858M

npy

npy是numpy自帶的一種保存格式,惟一的缺點是隻能保存numpy的格式,因此須要將pandas先轉成numpy才行,爲了公平,這裏咱們會算上轉換的時間

# 寫入
with open('./df_npy.npy', "wb") as f:
    np.save(f, arr=df.values)
# 讀取
with open('./df_npy.npy', "rb") as f:
    df_array = np.load(f, allow_pickle=True)
df = pd.DataFrame(df_array)

寫入時間花費:21 s

讀取時間花費:14.8 s

所需存儲空間:620M

hdf

層次數據格式(HDF)是自描述的,容許應用程序在沒有外部信息的狀況下解釋文件的結構和內容。一個HDF文件能夠包含一系列相關對象,這些對象能夠做爲一個組或單個對象進行訪問。

這裏將使用pandas自帶的to_hdf()方法,該方法默認是用的HDF5格式

# 寫入
df.to_hdf('df_hdf.h5', key='df')
# 讀取
df = pd.read_hdf('df_hdf.h5', key='df')

寫入時間花費:3.96 s

讀取時間花費:4.13 s

所需存儲空間:1.5G

已廢棄 msgpack

pandas支持msgpack格式的對象序列化。他是一種輕量級可移植的二進制格式,同二進制的JSON相似,具備高效的空間利用率以及不錯的寫入(序列化)和讀取(反序列化)性能。

從0.25版本開始,不推薦使用msgpack格式,而且以後的版本也將刪除它。推薦使用pyarrow對pandas對象進行在線的轉換。

read_msgpack() (opens new window)僅在pandas的0.20.3版本及如下版本兼容。

parquet

Apache Parquet爲數據幀提供了分區的二進制柱狀序列化。它的設計目的是使數據幀的讀寫效率,並使數據共享跨數據分析語言容易。Parquet可使用多種壓縮技術來儘量地縮小文件大小,同時仍然保持良好的讀取性能。

這裏須要使用到pyarrow裏面的方法來進行操做

# 寫入
pq.write_table(pa.Table.from_pandas(df), 'df_parquet.parquet')
# 讀取
df = pq.read_table('df_parquet.parquet').to_pandas()

寫入時間花費:3.47 s

讀取時間花費:1.85 s

所需存儲空間:426M

feature

Feather是一種可移植的文件格式,用於存儲內部使用Arrow IPC格式的Arrow表或數據幀(來自Python或R等語言)。Feather是在Arrow項目早期建立的,做爲Python和R的快速、語言無關的數據幀存儲概念的證實。

這裏須要使用到pyarrow裏面的方法來進行操做

# 寫入
feather.write_feather(df, 'df_feather.feather')
# 讀取
df = feather.read_feather('df_feather.feather')

寫入時間花費:1.9 s

讀取時間花費:1.52 s

所需存儲空間:715M

總結

對比表格

文件類型 讀取時間(s) 寫入時間(s) 存儲空間(MB)
csv 78.00 11.80 1,300
pickle 2.89 2.61 858
npy 21.00 14.80 620
hdf 3.96 4.13 1,500
parquet 3.47 1.85 426
feature 1.90 1.52 715

時間對比

讀寫時間對比.png

空間對比

存儲空間對比.png

能夠看出parquet會是一個保存文件的最好選擇,雖然時間上比feature略慢一點,但空間上有着更大的優點。

相關文章
相關標籤/搜索