[英]How to reversibly store and load a Pandas dataframe to/from disk
现在我每次运行脚本时都会导入一个相当大的CSV
作为 dataframe 。 是否有一个好的解决方案可以让 dataframe 在两次运行之间始终可用,这样我就不必花费所有时间等待脚本运行?
df.to_pickle(file_name) # where to save it, usually as a .pkl
然后您可以使用以下方法加载它:
df = pd.read_pickle(file_name)
注意:在 0.11.1 之前, save
和load
是唯一的方法(它们现在已被弃用,分别支持to_pickle
和read_pickle
)。
另一个流行的选择是使用HDF5 ( pytables ),它为大型数据集提供非常快的访问时间:
import pandas as pd
store = pd.HDFStore('store.h5')
store['df'] = df # save it
store['df'] # load it
食谱中讨论了更高级的策略。
从 0.13 开始,还有msgpack可能更适合互操作性,作为 JSON 的更快替代品,或者如果您有 python 对象/文本重数据(请参阅此问题)。
虽然已经有一些答案,但我找到了一个很好的比较,他们尝试了几种方法来序列化 Pandas DataFrames: Efficiently Store Pandas DataFrames 。
他们比较:
在他们的实验中,他们序列化了一个包含 1,000,000 行的 DataFrame,其中两列分别测试:一列包含文本数据,另一列包含数字。 他们的免责声明说:
您不应该相信以下内容可以概括为您的数据。 您应该查看自己的数据并自己运行基准测试
他们所引用的测试的源代码可在线获得。 由于这段代码不能直接工作,我做了一些小改动,你可以在这里得到: serialize.py我得到了以下结果:
他们还提到,通过将文本数据转换为分类数据,序列化速度要快得多。 在他们的测试中大约快 10 倍(另请参阅测试代码)。
编辑:pickle 比 CSV 更高的时间可以通过使用的数据格式来解释。 默认情况下, pickle
使用可打印的 ASCII 表示,从而生成更大的数据集。 然而,从图中可以看出,使用较新的二进制数据格式(版本 2, pickle-p2
)的pickle-p2
加载时间要低得多。
其他一些参考:
numpy.fromfile
是最快的。如果我理解正确,您已经在使用pandas.read_csv()
但希望加快开发过程,这样您就不必每次编辑脚本时都加载文件,对吗? 我有几点建议:
您可以使用pandas.read_csv(..., nrows=1000)
仅加载 CSV 文件的一部分以仅加载表的顶部位,同时进行开发
将 csv 转换为HDF5 表
更新使用DataFrame.to_feather()
和pd.read_feather()
以pd.read_feather()
的 R 兼容羽毛二进制格式存储数据(在我手中,在数字数据上比pandas.to_pickle()
略快,在字符串数据上快得多)。
您可能也对 stackoverflow 上的这个答案感兴趣。
泡菜效果很好!
import pandas as pd
df.to_pickle('123.pkl') #to save the dataframe, df to 123.pkl
df1 = pd.read_pickle('123.pkl') #to load 123.pkl back to the dataframe df
您可以使用羽毛格式文件。 它非常快。
df.to_feather('filename.ft')
Pandas DataFrames 有to_pickle
函数,这对于保存 DataFrame 很有用:
import pandas as pd
a = pd.DataFrame({'A':[0,1,0,1,0],'B':[True, True, False, False, False]})
print a
# A B
# 0 0 True
# 1 1 True
# 2 0 False
# 3 1 False
# 4 0 False
a.to_pickle('my_file.pkl')
b = pd.read_pickle('my_file.pkl')
print b
# A B
# 0 0 True
# 1 1 True
# 2 0 False
# 3 1 False
# 4 0 False
我更喜欢使用 numpy 文件,因为它们快速且易于使用。 这是保存和加载具有 1 列 100 万个点的数据帧的简单基准。
import numpy as np
import pandas as pd
num_dict = {'voltage': np.random.rand(1000000)}
num_df = pd.DataFrame(num_dict)
使用 ipython 的%%timeit
魔法函数
%%timeit
with open('num.npy', 'wb') as np_file:
np.save(np_file, num_df)
输出是
100 loops, best of 3: 5.97 ms per loop
将数据加载回数据帧
%%timeit
with open('num.npy', 'rb') as np_file:
data = np.load(np_file)
data_df = pd.DataFrame(data)
输出是
100 loops, best of 3: 5.12 ms per loop
不错!
如果您使用 python 2 保存 numpy 文件,然后尝试使用 python 3 打开(反之亦然),则会出现问题。
https://docs.python.org/3/library/pickle.html
pickle 协议格式:
协议版本 0 是原始的“人类可读”协议,向后兼容早期版本的 Python。
协议版本 1 是一种旧的二进制格式,它也与早期版本的 Python 兼容。
协议版本 2 是在 Python 2.3 中引入的。 它提供了更有效的新型类酸洗。 有关协议 2 带来的改进的信息,请参阅 PEP 307。
Python 3.0 中添加了协议版本 3。 它对字节对象有明确的支持,并且不能被 Python 2.x 取消。 这是默认协议,当需要兼容其他 Python 3 版本时推荐使用的协议。
Python 3.4 中添加了协议版本 4。 它增加了对超大对象的支持,酸洗更多种类的对象,以及一些数据格式优化。 有关协议 4 带来的改进的信息,请参阅 PEP 3154。
另一个非常新鲜的to_pickle()
测试。
我总共有25 个.csv
文件需要处理,最终的dataframe
包含大约200 万个项目。
(注意:除了加载 .csv 文件,我还操作一些数据并通过新列扩展数据框。)
浏览所有25 个.csv
文件并创建数据框大约需要14 sec
。
从pkl
文件加载整个数据帧需要不到1 sec
Arctic是 Pandas、numpy 和其他数字数据的高性能数据存储。 它位于 MongoDB 之上。 对于 OP 来说可能有点矫枉过正,但值得一提的是其他在这篇文章中绊倒的人
import pickle
example_dict = {1:"6",2:"2",3:"g"}
pickle_out = open("dict.pickle","wb")
pickle.dump(example_dict, pickle_out)
pickle_out.close()
上面的代码将保存pickle文件
pickle_in = open("dict.pickle","rb")
example_dict = pickle.load(pickle_in)
这两行将打开保存的泡菜文件
总体转移到 pyarrow/feather(来自 pandas/msgpack 的弃用警告)。 但是,我对 pyarrow 有一个挑战,在规范中具有瞬态数据用 pyarrow 0.15.1 序列化不能用 0.16.0 ARROW-7961反序列化。 我正在使用序列化来使用 redis,因此必须使用二进制编码。
我重新测试了各种选项(使用 jupyter notebook)
import sys, pickle, zlib, warnings, io
class foocls:
def pyarrow(out): return pa.serialize(out).to_buffer().to_pybytes()
def msgpack(out): return out.to_msgpack()
def pickle(out): return pickle.dumps(out)
def feather(out): return out.to_feather(io.BytesIO())
def parquet(out): return out.to_parquet(io.BytesIO())
warnings.filterwarnings("ignore")
for c in foocls.__dict__.values():
sbreak = True
try:
c(out)
print(c.__name__, "before serialization", sys.getsizeof(out))
print(c.__name__, sys.getsizeof(c(out)))
%timeit -n 50 c(out)
print(c.__name__, "zlib", sys.getsizeof(zlib.compress(c(out))))
%timeit -n 50 zlib.compress(c(out))
except TypeError as e:
if "not callable" in str(e): sbreak = False
else: raise
except (ValueError) as e: print(c.__name__, "ERROR", e)
finally:
if sbreak: print("=+=" * 30)
warnings.filterwarnings("default")
随着以下对我的数据帧的结果(在out
jupyter变量)
pyarrow before serialization 533366
pyarrow 120805
1.03 ms ± 43.9 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pyarrow zlib 20517
2.78 ms ± 81.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
msgpack before serialization 533366
msgpack 109039
1.74 ms ± 72.8 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
msgpack zlib 16639
3.05 ms ± 71.7 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
pickle before serialization 533366
pickle 142121
733 µs ± 38.3 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pickle zlib 29477
3.81 ms ± 60.4 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
feather ERROR feather does not support serializing a non-default index for the index; you can .reset_index() to make the index into column(s)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
parquet ERROR Nested column branch had multiple children: struct<x: double, y: double>
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
羽毛和镶木地板不适用于我的数据框。 我将继续使用pyarrow。 不过我会补充泡菜(无压缩)。 写入缓存存储 pyarrow 和 pickle 序列化表单时。 如果 pyarrow 反序列化失败,则从缓存回退读取到 pickle 时。
这里有很多很棒和足够的答案,但我想发布一个我在 Kaggle 上使用的测试,其中大 df 由不同的 Pandas 兼容格式保存和读取:
https://www.kaggle.com/pedrocouto39/fast-reading-w-pickle-feather-parquet-jay
我不是作者或作者的朋友,但是,当我读到这个问题时,我认为在那里值得一提。
CSV:1 分钟 42 秒泡菜:4.45 秒羽毛:4.35 秒镶木地板:8.31 秒 Jay:8.12 毫秒或 0.0812 秒(极快!)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.