【问题标题】:Python - Fast HDF5 Time Series Data QueriesPython - 快速 HDF5 时间序列数据查询
【发布时间】:2017-05-24 03:35:48
【问题描述】:

我需要对来自 HDF5 数据库的特定时间跨度的时间序列数据进行大量连续查询(数据以秒为单位存储,并不总是“连续”,我只知道开始和结束时间)。因此,我想知道是否有比我当前的代码更快的解决方案,其灵感来自this answer

import pandas as pd
from pandas import HDFStore

store = HDFStore(pathToStore)
dates = pd.date_range(start=start_date,end=end_date, freq='S')
index = store.select_column('XAU','index')
ts    = store.select('XAU', where=index[index.isin(dates)].index)

非常感谢任何 cmets 和建议,谢谢!

【问题讨论】:

    标签: python-3.x pandas time-series hdf5


    【解决方案1】:

    让我们测试一下吧!

    生成 1M 行 DF:

    In [129]: df = pd.DataFrame({'val':np.random.rand(10**6)}, index=pd.date_range('1980-01-01', freq='19S', periods=10**6))
    
    In [130]: df.shape
    Out[130]: (1000000, 1)
    
    In [131]: df.head()
    Out[131]:
                              val
    1980-01-01 00:00:00  0.388980
    1980-01-01 00:00:19  0.916917
    1980-01-01 00:00:38  0.894360
    1980-01-01 00:00:57  0.235797
    1980-01-01 00:01:16  0.577791
    

    让我们洗牌:

    In [132]: df = df.sample(frac=1)
    
    In [133]: df.head()
    Out[133]:
                              val
    1980-07-04 12:10:11  0.898648
    1980-07-08 20:37:39  0.563325
    1980-03-10 00:06:12  0.449458
    1980-08-07 02:01:42  0.511847
    1980-02-28 21:09:43  0.757327
    

    将生成的 DF 存储到 HDF5 文件中(注意:默认情况下,只有索引会被索引,因此如果您还要按其他列搜索,请使用 data_columns 参数):

    In [134]: store = pd.HDFStore('d:/temp/test_time_ser.h5')
    
    In [135]: store.append('XAU', df, format='t')
    
    In [136]: store.close()
    
    In [140]: store = pd.HDFStore('d:/temp/test_time_ser.h5')
    

    我们来测试select(where="<query>")方法:

    In [141]: store.select('XAU', where="index >= '1980-04-04' and index<= '1980-05-01'").head()
    Out[141]:
                              val
    1980-04-13 07:22:05  0.391409
    1980-04-25 14:23:07  0.400838
    1980-04-10 12:32:08  0.136346
    1980-04-09 18:58:35  0.944389
    1980-04-13 22:34:05  0.115643
    

    衡量绩效:

    In [142]: %timeit store.select('XAU', where="index >= '1980-04-04' and index<= '1980-05-01'")
    1 loop, best of 3: 755 ms per loop
    

    让我们将其与您当前的方法进行比较:

    In [144]: dates = pd.date_range(start='1980-04-04',end='1980-05-01', freq='S')
    
    In [145]: index = store.select_column('XAU','index')
    
    In [146]: store.select('XAU', where=index[index.isin(dates)].index).head()
    Out[146]:
                              val
    1980-04-13 07:22:05  0.391409
    1980-04-25 14:23:07  0.400838
    1980-04-10 12:32:08  0.136346
    1980-04-09 18:58:35  0.944389
    1980-04-13 22:34:05  0.115643
    
    In [147]: %timeit store.select('XAU', where=index[index.isin(dates)].index)
    1 loop, best of 3: 8.13 s per loop
    

    更新:让我们做同样的测试,但这次假设索引(时间序列)是排序的

    In [156]: df = pd.DataFrame({'val':np.random.rand(10**6)}, index=pd.date_range('1980-01-01', freq='19S', periods=10**6))
    
    In [157]: df.shape
    Out[157]: (1000000, 1)
    
    In [164]: store.close()
    
    In [165]: store = pd.HDFStore('d:/temp/test_time_ser2.h5')
    
    In [166]: store.append('XAU', df, format='t')
    
    In [167]: %timeit store.select('XAU', where="index >= '1980-04-04' and index<= '1980-05-01'")
    1 loop, best of 3: 253 ms per loop
    
    In [168]: %timeit store.select('XAU', where=index[index.isin(dates)].index)
    1 loop, best of 3: 8.13 s per loop
    

    【讨论】:

    • 这太棒了,谢谢。你能这么好心,写一句为什么第一个选项更快吗?
    • @Tim, IMO isin() 与“范围扫描”(Oracle Cost Base Optimizer 术语)相比具有巨大的开销。我们需要将列表中的所有值与一个系列(向量)进行比较。当我们进行范围扫描("index &gt;= '1980-04-04' and index&lt;= '1980-05-01'")时,我们只需要比较两个值(范围边界)
    • 您的索引是否在 HDF 文件中排序?它可能会影响我们的测试。我认为它没有排序
    • 很好,几乎一样,感谢您的努力!
    • @Tim,我正在测试同一个 HDF5 文件 - 现在我已经修复了它。 “范围扫描”方法的速度提高了约 3 倍,.isin() - 保持不变...
    猜你喜欢
    • 1970-01-01
    • 2018-08-16
    • 2011-07-19
    • 2021-04-19
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多