pickle文件加载时间

3

我只是在测试哪种文件格式最适合我的问题,并对几种格式进行了基准测试。在这样做的过程中,我发现了以下,在我看来很奇怪的加载文件时差异。

我使用以下代码创建了一个随机大型数据框以进行测试(因为我的问题使用时间序列数据,所以也用于我的示例):

rows = 5000000
cols = 50

df = pd.DataFrame(
    data=np.random.rand(rows, cols),
    index=pd.date_range(
        start='2014-01-01',
        periods=rows,
        freq='min'
    ),
)

然后我使用df.to_pickle('test.pkl')保存了DataFrame,并开始测试加载时间。由于我处理的是大型数据集,我还想知道当仅需要时间序列的一部分时加载时间如何扩展。我主要使用这个来查看其他能够只加载文件的一部分的格式是否能够在这样做时获得更小的加载时间。由于pickle文件需要完全加载,所以我只包含了一个.loc[time_stamp:]以得到相同的切片结果。这是我的结果:

In [1]: %timeit pd.read_pickle('test.pkl')
Out[1]: 1.94 s ± 182 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [2]: %timeit pd.read_pickle('test.pkl').loc[pd.to_datetime('20200101 00:00'):]
Out[2]: 1.73 s ± 237 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

我知道时差不大,但我在一天中多次测试过,第二种方法(使用切片)始终更快。这就引出了我的“问题”。为什么使用.loc[time_stamp:]的加载方法会更快?我认为这两种尝试完全相同,即加载整个pickle文件。唯一的区别是在第二种方法中使用了大约一半的DataFrame,这不应该有太大的区别。我错过了什么吗?
下一个问题是:这是在使用pickle时节省时间的方法吗?只需在加载它的行中切片DataFrame?
希望有人能对此有所了解,或者测试相同的事情并用我的观察结果证明我是错误的。

你使用pickle的原因是什么,相比之下,为什么不使用to_csv呢? - user12932966
正如我所写的,我目前正在测试不同的文件格式,但有时候我更喜欢使用pickle,因为它在写入/读取方面比其他格式要快得多。 - JD.
这是一个很好的问题。我尝试在pandas文档中找到相关信息,但没有找到任何有用的内容。然后我假设优化是在pickle方面完成的,但事实证明,在数组上执行类似操作(with open(file_path, "rb") as f:接着 pickle.load(f)[:50000000])会更慢,所以我真的不知道发生了什么。 - user12932966
1个回答

1

我对timeit的准确性持怀疑态度,因此我尝试了类似的方法,稍微增加了DataFrame的大小:

rows = 10000000
cols = 100
df = pd.DataFrame(
    data=np.random.rand(rows, cols),
    index=pd.date_range(
        start='2014-01-01',
        periods=rows,
        freq='min'
    ),
)

起初我能够复制您的问题:

%timeit pd.read_pickle(F)
2.67 s ± 362 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit pd.read_pickle(F).loc[pd.to_datetime('20200101 00:00'):]
2.51 s ± 30.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

但事实证明,我们只是被(我猜测)处理器缓存所欺骗了;两者中更快的操作始终是最新的;在这里,我先运行切片操作,再进行直接加载:

%timeit pd.read_pickle(F).loc[pd.to_datetime('20200101 00:00'):]
2.87 s ± 879 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit pd.read_pickle(F)
2.64 s ± 34.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

如果我们再运行几次timeit,就会看到预期的结果(切片方法稍微慢一点):
%timeit pd.read_pickle(F).loc[pd.to_datetime('20200101 00:00'):]
2.66 s ± 87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit pd.read_pickle(F)
2.63 s ± 70.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

有趣,我会测试你的方法并看看是否能够复现。我在测试时认为我已经切换了timeit的顺序,但也许我犯了一个错误。谢谢。 - JD.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接