【问题标题】:Is there aother reason to use pickle instead of excel to store pandas dataframes rather than IO?还有其他理由使用pickle而不是excel来存储熊猫数据帧而不是IO吗?
【发布时间】:2020-11-20 20:53:43
【问题描述】:

我正在创建一个小的熊猫数据集。我认为这比尝试将其改进为 SQLite 更好。

我正在选择数据集的格式。对于我的初始加载,与使用 Excel 相比,它减少了 45% 的文件大小。但是因为很小,所以是 585KB 的 45%。当与 CSV 比较时,它只是小了一点。

我认为 Excel 让我对数据有一定的灵活性,我愿意支付 IO 的价格。我错过了 Pickle 的一些优势吗?

【问题讨论】:

  • 可能不会。至少不适用于这个用例。
  • 如果数据框中的某些元素是真正的 Python 对象,如字典、列表等......也许使用 pickle 进行数据序列化是更好的选择,因为读取时,它会保留其类型。这实际上取决于用例、阅读频率以及阅读速度等...
  • 除非您还在 Excel 应用程序中使用数据,否则您实际上不会从 Excel 格式所需的开销中获得任何好处。我建议您研究二进制格式,例如广泛使用的parquetfeather(使用pandas 更快,但不是普遍可读)...我没有使用过HDF5,但根据这个答案它有很多好处@987654321 @

标签: python pandas pickle


【解决方案1】:

我刚刚重新运行了我的性能测试。 msgpackfeatherparquet 已更改接口或已删除,因此不再工作。

我的用例更多地是围绕使用哪种序列化格式来缓存 Redis 缓存中的数据帧。没有明显的赢家

  1. 使用 pickle 可以,但您会收到来自 pandas 的弃用警告,并且确实保持向后兼容性。这是一种仅限 python 的序列化格式
  2. 使用 pyarrow 提供了更多的可移植性,可以在 python、java、...中使用。但是它不保持跨版本的向后兼容性ARROW-7961
  3. 是否再次压缩是基于空间/时间权衡的决定

我继续使用pyarrow 并对此感到满意。但是,如果发现暂时的向后兼容性问题,我的代码将自动切换到 pickle

import sys, pickle, zlib, warnings, io
import pyarrow as pa

t = list(pd.date_range(dt.datetime(2020,1,1), dt.datetime(2020,1,3), freq='min'))
uh = [random.randint(0,50) for e in t]
out = pd.DataFrame({"timestamp":t, "user_holding":uh})

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(path=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")

输出

pyarrow before serialization 46256
pyarrow 51901
630 µs ± 59.9 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pyarrow zlib 20041
2.72 ms ± 53.2 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=
pickle before serialization 46256
pickle 47166
96.7 µs ± 5.02 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
pickle zlib 19276
1.95 ms ± 25.3 µs per loop (mean ± std. dev. of 7 runs, 50 loops each)
=+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+==+=

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 2021-09-12
    • 2014-06-03
    • 1970-01-01
    • 2016-09-12
    • 2015-08-15
    • 2021-10-18
    相关资源
    最近更新 更多