如何使用Pandas存储数据框

时间:2013-06-13 23:05:37

标签: python pandas dataframe

现在我每次运行脚本时都会导入一个相当大的CSV作为数据帧。是否有一个很好的解决方案可以保持数据帧在两次运行之间始终可用,因此我不必花费所有时间等待脚本运行?

13 个答案:

答案 0 :(得分:369)

最简单的方法是pickle使用to_pickle

df.to_pickle(file_name)  # where to save it, usually as a .pkl

然后你可以使用以下方法加载它:

df = pd.read_pickle(file_name)

注意:在0.11.1之前saveload是实现此目的的唯一方法(它们现在已被弃用,分别支持to_pickleread_pickle )。


另一个受欢迎的选择是使用HDF5pytables),为大型数据集提供very fast次访问时间:

store = HDFStore('store.h5')

store['df'] = df  # save it
store['df']  # load it

cookbook中讨论了更高级的策略。


从0.13开始,还有msgpack可能更适合互操作性,作为JSON的更快替代方案,或者如果你有python对象/文本大量数据(参见this question)。

答案 1 :(得分:75)

虽然已经有一些答案,但我发现了一个很好的比较,他们尝试了几种方法来序列化Pandas DataFrames:Efficiently Store Pandas DataFrames

他们比较:

  • pickle:原始ASCII数据格式
  • cPickle,一个C库
  • pickle-p2:使用较新的二进制格式
  • json:standardlib json library
  • json-no-index:喜欢json,但没有索引
  • msgpack:二进制JSON替代
  • CSV
  • hdfstore:HDF5存储格式

在他们的实验中,他们序列化了1,000,000行的DataFrame,并分别测试了两列:一列是文本数据,另一列是数字。他们的免责声明说:

  

您不应相信以下内容会对您的数据进行推广。您应该查看自己的数据并自己运行基准

他们引用的测试的源代码可用online。由于此代码无法直接使用,因此我进行了一些小的更改,您可以在此处进行更改:serialize.py  我得到了以下结果:

time comparison results

他们还提到,通过将文本数据转换为categorical数据,序列化速度更快。在他们的测试中大约快10倍(也见测试代码)。

编辑:pickle比CSV更高的时间可以用所使用的数据格式来解释。默认情况下,pickle使用可打印的ASCII表示,生成更大的数据集。从图中可以看出,使用较新的二进制数据格式(版本2,pickle-p2)的pickle加载时间要低得多。

其他一些参考文献:

答案 2 :(得分:29)

如果我理解正确,您已经在使用pandas.read_csv()但是希望加快开发过程,这样您就不必在每次编辑脚本时都加载文件,是吗?我有一些建议:

  1. 您可以使用pandas.read_csv(..., nrows=1000)仅加载部分CSV文件,只加载表格的顶部位,而您正在进行开发

  2. 使用ipython进行交互式会话,以便在编辑和重新加载脚本时将pandas表保留在内存中。

  3. 将csv转换为HDF5 table

  4. 已更新使用DataFrame.to_feather()pd.read_feather()以超快速的R兼容feather二进制格式存储数据(在我手中,比数字数据上的pandas.to_pickle()略快,字符串数据上的速度要快得多。)

  5. 您可能也对stackoverflow上的this answer感兴趣。

答案 3 :(得分:4)

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

答案 4 :(得分:3)

您可以使用羽毛格式文件。它非常快。

df.to_feather('filename.ft')

答案 5 :(得分:3)

如上所述,有不同的选项和文件格式(HDF5JSONCSVparquetSQL)来存储数据帧。但是,pickle不是一等公民(取决于您的设置),因为:

1)pickle是潜在的安全风险。形成Python documentation for pickle

  

警告 pickle模块不能防止错误或错误   恶意构建的数据。切勿破坏从计算机接收到的数据   不受信任或未经身份验证的来源。

2)pickle很慢。查找herehere基准。

取决于您的设置/用法,两个限制均不适用,但我不建议将pickle作为熊猫数据帧的默认持久性。

答案 6 :(得分:2)

数字数据的Numpy文件格式非常快

我更喜欢使用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

没有坏!

CONS

如果使用python 2保存numpy文件然后尝试使用python 3打开(反之亦然),则会出现问题。

答案 7 :(得分:1)

使用to_pickle()进行的另一项全新测试。

我总共有 25 .csv文件要处理,最后的dataframe由大约 2M 个项目组成。

(注意:除了加载.csv文件之外,我还操纵一些数据并通过新的列扩展数据框架。)

遍历所有 25 .csv 文件并创建数据框大约需要14 sec

pkl文件加载整个数据帧所需的时间少于1 sec

答案 8 :(得分:1)

Arctic是用于Pandas,numpy和其他数字数据的高性能数据存储。它位于MongoDB之上。可能对OP来说是过分杀伤,但值得在这篇文章中绊脚石的其他人

答案 9 :(得分:0)

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)

这两行将打开已保存的pickle文件

答案 10 :(得分:0)

https://docs.python.org/3/library/pickle.html

pickle协议格式:

协议版本0是原始的“人类可读”协议,并且与Python的早期版本向后兼容。

协议版本1是旧的二进制格式,也与Python的早期版本兼容。

协议版本2是在Python 2.3中引入的。它提供了更高效的新型类酸洗。有关协议2带来的改进的信息,请参阅PEP 307。

协议版本3已在Python 3.0中添加。它具有对byte对象的显式支持,并且不能被Python 2.x解开。这是默认协议,当需要与其他Python 3版本兼容时,建议使用该协议。

协议版本4已在Python 3.4中添加。它增加了对非常大的对象的支持,腌制更多种类的对象以及一些数据格式优化。有关协议4带来的改进的信息,请参阅PEP 3154。

答案 11 :(得分:0)

各个版本的金字塔兼容性

总体行动已转向pyarrow / feather(来自pandas / msgpack的弃用警告)。但是,我对具有 transient规范的pyarrow提出了挑战,使用pyarrow 0.15.1序列化的数据无法使用0.16.0 ARROW-7961进行反序列化。我正在使用序列化来使用Redis,因此必须使用二进制编码。

我已经重新测试了各种选项(使用jupyter笔记本)

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反序列化失败,则从缓存回退到泡菜时读取。

答案 12 :(得分:0)

这里有很多很棒和足够的答案,但我想发布一个我在 Kaggle 上使用的测试,其中大 df 由不同的 Pandas 兼容格式保存和读取:

https://www.kaggle.com/pedrocouto39/fast-reading-w-pickle-feather-parquet-jay

我不是这个问题的作者或作者的朋友,但是,当我读到这个问题时,我认为这里值得一提。

<块引用>

CSV:1 分钟 42 秒泡菜:4.45 秒羽毛:4.35 秒镶木地板:8.31 秒杰伊:8.12 毫秒 或 0.0812 秒(极快!)