Pandas按日期和时间范围查询read_hdf
我有个问题,想了解一下如何在pd.read_hdf这个函数中筛选结果。简单说,我有一个pandas的数据框(它的索引是np.datetime64格式),我把它存进了一个hdf5文件里。这里没有什么复杂的操作,也没有使用层级结构之类的(也许我可以试试用上?)。下面是个例子:
Foo Bar
TIME
2014-07-14 12:02:00 0 0
2014-07-14 12:03:00 0 0
2014-07-14 12:04:00 0 0
2014-07-14 12:05:00 0 0
2014-07-14 12:06:00 0 0
2014-07-15 12:02:00 0 0
2014-07-15 12:03:00 0 0
2014-07-15 12:04:00 0 0
2014-07-15 12:05:00 0 0
2014-07-15 12:06:00 0 0
2014-07-16 12:02:00 0 0
2014-07-16 12:03:00 0 0
2014-07-16 12:04:00 0 0
2014-07-16 12:05:00 0 0
2014-07-16 12:06:00 0 0
接下来,我用以下命令把它存成一个.h5文件:
store = pd.HDFStore('qux.h5')
#generate df
store.append('data', df)
store.close()
然后,我会有另一个程序来访问这些数据,我想从中提取一些日期/时间的切片。比如说,我想要2014年7月14日到2014年7月15日之间的数据,并且只要12:02:00到12:04:00之间的时间。目前我用以下命令来获取这些数据:
pd.read_hdf('qux.h5', 'data', where='index >= 20140714 and index <= 20140715').between_time(start_time=datetime.time(12,2), end_time=datetime.time(12,4))
据我所知,如果我使用'where',那么整个原始数据集不会被全部读入内存。如果换句话说:
这个:
pd.read_hdf('qux.h5', 'data', where='index >= 20140714 and index <= 20140715')
和这个:
pd.read_hdf('qux.h5', 'data')['20140714':'20140715']
虽然最终结果是一样的,但背后处理的方式却不一样。所以我的问题是,是否有办法把时间范围的过滤(也就是 .between_time())放进我的where语句里?或者我应该以其他方式来构建我的hdf5文件?比如说,每天存一个表?
谢谢!
补充:
关于使用层级结构,我知道结构应该高度依赖于我如何使用这些数据。不过,如果我假设每个日期定义一个表(例如 'df/date_20140714', 'df/date_20140715', ...)。我可能会错,但以我查询日期/时间范围的例子来看;我可能会遭遇性能问题,因为我需要读取每个表,然后如果想要合并输出的话,还得把它们合在一起,对吧?
1 个回答
这里有一个使用条件筛选的例子。
下面是一个示例:
In [50]: pd.set_option('max_rows',10)
In [51]: df = DataFrame(np.random.randn(1000,2),index=date_range('20130101',periods=1000,freq='H'))
In [52]: df
Out[52]:
0 1
2013-01-01 00:00:00 -0.467844 1.038375
2013-01-01 01:00:00 0.057419 0.914379
2013-01-01 02:00:00 -1.378131 0.187081
2013-01-01 03:00:00 0.398765 -0.122692
2013-01-01 04:00:00 0.847332 0.967856
... ... ...
2013-02-11 11:00:00 0.554420 0.777484
2013-02-11 12:00:00 -0.558041 1.833465
2013-02-11 13:00:00 -0.786312 0.501893
2013-02-11 14:00:00 -0.280538 0.680498
2013-02-11 15:00:00 1.533521 -1.992070
[1000 rows x 2 columns]
In [53]: store = pd.HDFStore('test.h5',mode='w')
In [54]: store.append('df',df)
In [55]: c = store.select_column('df','index')
In [56]: where = pd.DatetimeIndex(c).indexer_between_time('12:30','4:00')
In [57]: store.select('df',where=where)
Out[57]:
0 1
2013-01-01 00:00:00 -0.467844 1.038375
2013-01-01 01:00:00 0.057419 0.914379
2013-01-01 02:00:00 -1.378131 0.187081
2013-01-01 03:00:00 0.398765 -0.122692
2013-01-01 04:00:00 0.847332 0.967856
... ... ...
2013-02-11 03:00:00 0.902023 1.416775
2013-02-11 04:00:00 -1.455099 -0.766558
2013-02-11 13:00:00 -0.786312 0.501893
2013-02-11 14:00:00 -0.280538 0.680498
2013-02-11 15:00:00 1.533521 -1.992070
[664 rows x 2 columns]
In [58]: store.close()
有几点需要注意。开始时会读取整个索引,通常这不会造成太大负担。如果真的很麻烦,你可以分块读取(提供开始和结束的位置,不过现在这样做有点麻烦)。目前的select_column
我认为也不能接受查询。
如果你有非常庞大的数据(比如几千万行,而且每行数据很宽),你可以考虑逐天处理(进行单独查询),这样可能会更高效。
重新组合数据是相对便宜的(通过concat
),所以不要害怕进行子查询(不过如果这样做太多,也可能会影响性能)。