【问题标题】:Using slicers on a multi-index在多索引上使用切片器
【发布时间】:2016-11-12 15:45:01
【问题描述】:

我有一个表单的数据框:

Contract  Date      
201501    2014-04-29    1416.0
          2014-04-30    1431.1
          2014-05-01    1430.6
          2014-05-02    1443.9
          2014-05-05    1451.6
          2014-05-06    1461.4
          2014-05-07    1456.0
          2014-05-08    1441.1
          2014-05-09    1437.8
          2014-05-12    1445.2
          2014-05-13    1458.2
          2014-05-14    1487.6
          2014-05-15    1477.6
          2014-05-16    1467.9
          2014-05-19    1484.9
          2014-05-20    1470.5
          2014-05-21    1476.9
          2014-05-22    1490.0
          2014-05-23    1473.3
          2014-05-27    1462.5
          2014-05-28    1456.3
          2014-05-29    1460.5
201507    2014-05-30    1463.5
          2014-06-02    1447.5
          2014-06-03    1444.4
          2014-06-04    1444.7
          2014-06-05    1455.9
          2014-06-06    1464.0

其中 Contract 和 Date 分别是 intdatetime64 类型的索引。

我想要的是选择一个日期范围。它的工作原理是:

df.reset_index('Contract', drop=True).loc['2014-09']

但我讨厌这个,因为它失去了索引/不是很愉快(我必须做很多这些)。

我想我应该可以这样做:

df.loc[:,'2014-09']

恢复 2014 年 9 月的所有数据。实际上,这是行不通的。我只能通过以下方式选择一天:

df.loc[:,'2014-09-02']

为什么我的多索引切片器不起作用?

【问题讨论】:

    标签: python pandas indexing dataframe slice


    【解决方案1】:

    Pandas 需要您明确说明您是选择层次索引的列还是子级别。在这种情况下,df.loc[:,'2014-09'] 失败,因为 pandas 尝试获取所有行,然后查找标记为 '2014-09' 的列(不存在)。

    相反,您需要同时提供多索引的两个级别列标签/切片。

    要从您的示例中选择所有 2014 年 5 月的数据,您可以编写:

    >>> df.loc[(slice(None), '2014-05'), :]                            
    Contract Date              
    201501   2014-05-01  1430.6
             2014-05-02  1443.9
             2014-05-05  1451.6
             2014-05-06  1461.4
             2014-05-07  1456.0
             2014-05-08  1441.1
             2014-05-09  1437.8
             2014-05-12  1445.2
             2014-05-13  1458.2
             2014-05-14  1487.6
             2014-05-15  1477.6
             2014-05-16  1467.9
             2014-05-19  1484.9
             2014-05-20  1470.5
             2014-05-21  1476.9
             2014-05-22  1490.0
             2014-05-23  1473.3
             2014-05-27  1462.5
             2014-05-28  1456.3
             2014-05-29  1460.5
    201507   2014-05-30  1463.5
    

    这里[(slice(None), '2014-05'), :] 转换为[:, '2014-05'] 的切片用于行,[:] 用于列。

    引入pd.IndexSlice 对象是为了使这些切片语义更容易一些:

    >>> idx = pd.IndexSlice
    >>> df.loc[idx[:, '2014-05'], :]
    # same slice of DataFrame
    

    【讨论】:

    • 这绝对有效吗?当我尝试这样做时,它似乎只返回所有数据,而不是相应的切片(因此它可以在您的示例中使用有限的数据集,但不适用于我的扩展数据集)。
    • @cjm2671,您可以尝试使用您的示例数据集重现它吗?
    • @cjm2671:它应该可以工作;我不确定如何返回所有行,除非您也 slice 在第二级使用更早的日期,例如df.loc[idx[:, '2013-05':], :]。正如 MaxU 建议的那样,也许您可​​以在较小的数据集上重现此问题,以便我们可以进一步调查?
    • @ajcr,你知道为什么df.loc[(slice(None), '2014-05'), :] 有效而df.ix[(slice(None), '2014-05'), :] 无效吗?
    • 好的,我确实让它工作了。我在上面犯了一个错误-它是具有多索引的 pd.Series,而不是 DataFrame。当我申请 to_frame() 时,它起作用了。我能问一下,为什么这不适用于系列?
    【解决方案2】:

    您可以使用pd.Indexslice 根据您的MultiIndex 的每个level 的范围进行选择,就像这样(see docs):

    idx = pd.IndexSlice
    df.loc[idx[:, '2014-05'], :]
    

    得到:

    Contract Date              
    201501   2014-05-01  1430.6
             2014-05-02  1443.9
             2014-05-05  1451.6
             2014-05-06  1461.4
             2014-05-07  1456.0
             2014-05-08  1441.1
             2014-05-09  1437.8
             2014-05-12  1445.2
             2014-05-13  1458.2
             2014-05-14  1487.6
             2014-05-15  1477.6
             2014-05-16  1467.9
             2014-05-19  1484.9
             2014-05-20  1470.5
             2014-05-21  1476.9
             2014-05-22  1490.0
             2014-05-23  1473.3
             2014-05-27  1462.5
             2014-05-28  1456.3
             2014-05-29  1460.5
    201507   2014-05-30  1463.5
    

    【讨论】:

      【解决方案3】:

      您可以使用.dt accessor 提取九月份的所有值,如下所示:

      df.loc[(pd.to_datetime(df['Date']).dt.month == 9)]
      

      时间限制:

      timeit df.loc[(pd.to_datetime(df['Date']).dt.month == 5)]
      1000 loops, best of 3: 796 µs per loop
      

      【讨论】:

        猜你喜欢
        • 2018-05-20
        • 2021-12-31
        • 2014-10-21
        • 2018-11-22
        • 2021-08-25
        • 2015-03-16
        • 2018-10-31
        • 2019-10-28
        • 2018-08-20
        相关资源
        最近更新 更多