为什么 pd.DataFrame 泡菜的大小在 df.to_pickle 和本地 Python 泡菜之间差异如此之大?

Why do pd.DataFrame pickle sizes vary so much between df.to_pickle and native Python pickle?

我有一个具有以下结构的 pandas 数据框 (pd.DataFrame):

In [175]: df.dtypes.value_counts()
Out[175]: 
int64      876
float64    206
object      76
bool         9
dtype: int64

In [176]: df.shape
Out[176]: (9764, 1167)

我已经通过以下三种方式将数据存储到磁盘:

In [170]: df.to_csv('df.csv')

In [171]: df.to_pickle('df_v1.pkl')

In [172]: import pickle
In [173]: with open('df_v2.pkl', 'wb') as handle:
   .....:     pickle.dump(df, handle)

磁盘上的文件大小如下:

df.csv:     26.4 MB 
df_v1.pkl:  90.5 MB
df_v2.pkl: 340.4 MB

csv 很小是可以理解的 - 它没有 pandas 开销来保存(也就是说,它不必保存数据帧数据类型等) 我不明白的是,为什么来自两种不同 pickle-ing 方法的 pickles 在大小上相差如此之大!另外,一个比另一个更受欢迎吗?那么向后兼容性呢?

查看 source code for to_pickle, pandas chooses the most efficient protocol possible when it pickles the DataFrame. By defaultpickle.dump 使用 ASCII 协议,这是文件大小方面效率最低的协议。这样做是为了确保兼容性,并使其更容易恢复,因为 ASCII 协议是人类可读的。

您的代码的等效项是将 pickle.dump 行更改为:

pickle.dump(df, handle, protocol=pickle.HIGHEST_PROTOCOL)

我只使用 to_pickle 方法,因为它会产生更清晰的代码。不应该有任何向后兼容性问题,除非您需要与 Python 的非常旧版本兼容; Python 2.3.

中引入了更高效的 pickle 协议

另一件需要注意的事情是 pandas 使用 cPickle 来提高性能,而不是 pickle 本身。这不应该影响文件大小,但这是两者之间的另一个潜在差异。一般来说,您应该尽可能使用 cPickle,只有在 cPickle.

不支持您想做的事情时才使用 pickle