Pickling pandas dataframe 文件大小乘以 5

Pickling pandas dataframe multiplies by 5 the file size

我正在用 pandas.read_csv 读取一个 800 Mb 的 CSV 文件,然后使用原始 Python pickle.dump(datfarame) 来保存它。结果是一个 4 Gb pkl 文件,因此 CSV 大小乘以 5。

我希望 pickle 能够压缩数据而不是扩展数据。还因为我可以对 CSV 文件进行 gzip 压缩,将其压缩为 200 Mb,除以 4。

我愿意加快我的程序的加载时间,并认为 pickling 会有所帮助,但考虑到磁盘访问是主要瓶颈我理解我宁愿压缩文件然后使用压缩选项来自 pandas.read_csv 以加快加载时间。

对吗?

pickling pandas dataframe 扩展数据大小是否正常?

你通常如何加快加载时间?

您使用 pandas 加载的数据大小限制是多少?

不要将 800MB 文件加载到内存中。它会增加你的加载时间。 Pickle 对象也需要更多时间来加载。而是将 csv 文件存储为 sqlite3(与 python 一起提供)table。然后根据需要每次查询table。

不确定为什么您认为 pickling 会压缩数据大小,pickling 会创建 python 对象的字符串版本,以便它可以作为 python 对象加载回来:

In [388]:

import sys
import os
df = pd.DataFrame({'a':np.arange(5)})
df.to_pickle(r'c:\data\df.pkl')
print(sys.getsizeof(df))
statinfo = os.stat(r'c:\data\df.pkl')
print(statinfo.st_size)
with open(r'c:\data\df.pkl', 'rb') as f:
    print(f.read())
56
700
b'\x80\x04\x95\xb1\x02\x00\x00\x00\x00\x00\x00\x8c\x11pandas.core.frame\x94\x8c\tDataFrame\x94\x93\x94)}\x94\x92\x94\x8c\x15pandas.core.internals\x94\x8c\x0cBlockManager\x94\x93\x94)}\x94\x92\x94(]\x94(\x8c\x11pandas.core.index\x94\x8c\n_new_Index\x94\x93\x94h\x0b\x8c\x05Index\x94\x93\x94}\x94(\x8c\x04data\x94\x8c\x15numpy.core.multiarray\x94\x8c\x0c_reconstruct\x94\x93\x94\x8c\x05numpy\x94\x8c\x07ndarray\x94\x93\x94K\x00\x85\x94C\x01b\x94\x87\x94R\x94(K\x01K\x01\x85\x94\x8c\x05numpy\x94\x8c\x05dtype\x94\x93\x94\x8c\x02O8\x94K\x00K\x01\x87\x94R\x94(K\x03\x8c\x01|\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK?t\x94b\x89]\x94\x8c\x01a\x94at\x94b\x8c\x04name\x94Nu\x86\x94R\x94h\rh\x0b\x8c\nInt64Index\x94\x93\x94}\x94(h\x11h\x14h\x17K\x00\x85\x94h\x19\x87\x94R\x94(K\x01K\x05\x85\x94h\x1f\x8c\x02i8\x94K\x00K\x01\x87\x94R\x94(K\x03\x8c\x01<\x94NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x89C(\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x94t\x94bh(Nu\x86\x94R\x94e]\x94h\x14h\x17K\x00\x85\x94h\x19\x87\x94R\x94(K\x01K\x01K\x05\x86\x94h\x1f\x8c\x02i4\x94K\x00K\x01\x87\x94R\x94(K\x03h5NNNJ\xff\xff\xff\xffJ\xff\xff\xff\xffK\x00t\x94b\x89C\x14\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x94t\x94ba]\x94h\rh\x0f}\x94(h\x11h\x14h\x17K\x00\x85\x94h\x19\x87\x94R\x94(K\x01K\x01\x85\x94h"\x89]\x94h&at\x94bh(Nu\x86\x94R\x94a}\x94\x8c\x060.14.1\x94}\x94(\x8c\x06blocks\x94]\x94}\x94(\x8c\x06values\x94h>\x8c\x08mgr_locs\x94\x8c\x08builtins\x94\x8c\x05slice\x94\x93\x94K\x00K\x01K\x01\x87\x94R\x94ua\x8c\x04axes\x94h\nust\x94bb.'

方法 to_csv 确实支持压缩,如 kwarg'gzip''bz2':

In [390]:

df.to_csv(r'c:\data\df.zip', compression='bz2')
statinfo = os.stat(r'c:\data\df.zip')
print(statinfo.st_size)
29

将 CSV 文件存储在某种数据库中并对其执行操作可能符合您的最佳利益,而不是像 Kathirmani 建议的那样将 CSV 文件加载到 RAM。您会看到您期望的加载时间加速,这仅仅是因为您每次加载脚本时都没有填满 800 Mb 的 RAM。

文件压缩和加载时间是您似乎要完成的两个相互冲突的因素。压缩 CSV 文件并加载需要 更多 时间;您现在添加了必须解压缩文件的额外步骤,但这并不能解决您的问题。

考虑将数据发送到 sqlite3 数据库的准备步骤,如下所述:Importing a CSV file into a sqlite3 database table using Python.

您现在很高兴能够查询数据的子集并将其快速加载到 pandas.DataFrame 以供进一步使用,如下所示:

from pandas.io import sql
import sqlite3

conn = sqlite3.connect('your/database/path')
query = "SELECT * FROM foo WHERE bar = 'FOOBAR';"

results_df = sql.read_frame(query, con=conn)
...

相反,您可以使用 pandas.DataFrame.to_sql() 保存这些以备后用。

您也可以使用 panda 的 pickle 方法来压缩您的数据。

保存数据帧:

df.to_pickle(filename)

加载它:

df = pd.read_pickle(filename)