为什么 df.to_pickle 和本机 Python pickle 之间的 pd.DataFrame pickle 大小差异如此之大?

ali*_*dry 5 python pickle dataframe pandas

我有一个具有以下结构的 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)
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

磁盘上文件的大小如下:

df.csv:     26.4 MB 
df_v1.pkl:  90.5 MB
df_v2.pkl: 340.4 MB
Run Code Online (Sandbox Code Playgroud)

csv是可以理解的小 - 它没有要保存的 pandas 开销(也就是说,它不必保存数据帧 dtypes 等)我不明白的是为什么pickle两种不同的pickle-ing 方法的 s 差异如此之大尺寸!另外,其中一个比另一个更受青睐吗?向后兼容性怎么样?

roo*_*oot 5

查看 的源代码to_pickle,pandas 在 pickle DataFrame 时会选择最有效的协议。默认情况下,pickle.dump使用 ASCII 协议,就文件大小而言,这是效率最低的协议。这样做是为了确保兼容性,并使其更容易恢复,因为 ASCII 协议是人类可读的。

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

pickle.dump(df, handle, protocol=pickle.HIGHEST_PROTOCOL)
Run Code Online (Sandbox Code Playgroud)

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

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