【问题标题】:Pandas multi-index best way to slice for ranges of subordinate levelsPandas 多索引对从属级别范围进行切片的最佳方法
【发布时间】:2015-04-03 14:22:29
【问题描述】:

我有两个关于 pandas 数据框多索引的问题。

假设我有一个数据框 df 如下:

                                   data
    port                           bm  pf
    sector instrument date
    1      A          2013-01-14    0   0
                      2013-01-15    5   5
                      2013-01-16   10  10
                      2013-01-17   15  15
                      2013-01-18   20  20

可以使用以下代码生成:

import pandas as pd
date = pd.bdate_range('2013-01-14','2013-01-20').repeat(5)
sector = [1,1,1,2,2] * 5
df = pd.DataFrame(dict(port=['pf']*25,sector=sector,instrument=list('ABCDE')*5,date=date,data=xrange(25)))
df = pd.concat([df,pd.DataFrame(dict(port=['bm']*25,sector=sector,instrument=list('ABCDE')*5,date=date,data=xrange(25)))],axis=0)
df = df.set_index(['port','sector','instrument','date'])
df = df.unstack('port')

我想得到两组结果:2013-01-17 的所有值和 2013-01-17 到系列结束的所有值。

首先我知道我可以使用以下方法之一:

idx = pd.IndexSlice
targetdate = pd.Timestamp('2013-01-17')
slicer = (slice(None),slice(None),targetdate)

1) df.loc[slicer,:]

2) df.xs(pd.Timestamp('2013-01-17'),level=2)

3)df.xs(slicer,)

4) df[idx[:,:,targetdate],:]

所有这些看起来都很笨重。我错过了更明显的方式吗?还有什么其他方法可以实现这一点。我想我希望有像df.loc(level=2)[targetdate] 这样的东西(当然这是行不通的)。

第二次我只提出了一个解决方案

query = df.index.get_level_values(2) >= pd.Timestamp('2013-01-17')
df[query]

还有没有更有效的方法来做到这一点?

最后的奖励问题:df.index.get_loc_level() 做什么?我觉得它应该对此有所帮助,但我不知道如何使用它。

谢谢

【问题讨论】:

    标签: python pandas multi-index


    【解决方案1】:

    我认为这种掩蔽,就像你正在做的那样,在这里会非常好:

    query = df.index.get_level_values(2) >= pd.Timestamp('2013-01-17')
    df[query]
    

    如果您在日期中有很多重复,您可以使用较低级别的内容来提高性能:

    query = (df.index.levels[2] >= pd.Timestamp("2013-01-17"))[df.index.labels[2]]
    df[query]
    

    我可能会为此大喊大叫...!但在某些情况下它会明显更快。


    get_loc_level 类似于 loc,即基于标签而不是按位置:

    获取请求的标签或元组的整数位置切片

    In [21]: df.index.get_loc_level(2)
    Out[21]:
    (slice(15, 25, None),
     MultiIndex(levels=[[u'A', u'B', u'C', u'D', u'E'], [2013-01-14 00:00:00, 2013-01-15 00:00:00, 2013-01-16 00:00:00, 2013-01-17 00:00:00, 2013-01-18 00:00:00]],
                labels=[[3, 3, 3, 3, 3, 4, 4, 4, 4, 4], [0, 1, 2, 3, 4, 0, 1, 2, 3, 4]],
                names=[u'instrument', u'date']))
    

    默认情况下它采用第一个索引,但您可以传入更多...

    In [21]: df.index.get_loc_level((1, "A"))
    Out[21]:
    (slice(0, 5, None), <class 'pandas.tseries.index.DatetimeIndex'>
     [2013-01-14, ..., 2013-01-18]
     Length: 5, Freq: None, Timezone: None)
    

    【讨论】:

    • 谢谢@Andy 我可以看看你对第一个问题有什么想法吗?除了我上面描述的四种之外,还有更有效的方法从日期索引中挑选项目吗? .. 并感谢您解释 get_loc_level。您有任何可以分享的用例示例吗?我可以在哪里应用它?
    • @TahnoonPasha tbh 我认为 get_loc_level 几乎是私有/低级的,我更喜欢使用xs(横截面),我认为它可以更好地描述功能。关于效率,尝试使用%timeit 的大框架/示例 - 我怀疑我的第二行将是最快的(这是在我所做的测试中,尽管我没有尝试所有排列) .
    猜你喜欢
    • 1970-01-01
    • 2021-08-25
    • 2014-12-17
    • 2018-06-06
    • 2016-12-12
    • 2014-07-30
    • 1970-01-01
    • 2016-02-21
    • 2018-11-22
    相关资源
    最近更新 更多