【问题标题】:Get the first and last element of sequences inside an level of an multindex pandas series获取多索引熊猫系列级别内序列的第一个和最后一个元素
【发布时间】:2019-03-26 22:22:01
【问题描述】:

我有一个系列的状态可以是真或假。它有一个 MultiIndex,第一级用于 ID,第二级用于每个 ID 中的情节,第三级用于记录状态的日期。

ID  Episode Date        Status
foo 1       2019-02-01  False
            2019-02-02  True
            2019-02-03  True
            2019-02-04  False
    2       2019-02-05  True
            2019-02-06  True
            2019-02-07  False
    3       2019-02-08  False
            2019-02-09  True
            2019-02-10  True
bar 1       2019-03-03  False
            2019-03-04  True
    2       2019-03-05  True
            2019-03-06  True
            2019-03-07  False
            2019-03-08  True
            2019-03-09  False

我想将某一集中的状态开始为真以及何时停止为真的日期提取到数据框中。对于这个例子,结果应该是这样的:

 ID Episode Start Dates             End Dates       
foo 1       2019-02-02              2019-03-03          
    2       2019-02-05              2019-02-06  
    3       2019-02-09              2019-02-10
bar 1       2019-03-04              2019-03-04
    2       2019-03-05, 2019-03-08  2019-03-06, 2019-03-08

【问题讨论】:

  • 检查你的输出栏 - 2
  • 谢谢,已更正
  • 为什么最后一行 2019-03-09 被选中了
  • 另一个错字...我试图用只有一天的“true”来做一个例子,但犯了一个错误...
  • 我已经添加了答案

标签: python pandas dataframe series


【解决方案1】:

检查使用 groupbycumsum 为组创建内部密钥,下一步我们根据 df 中的所有 True 值进行过滤,然后我们使用新密钥和 @987654325 进行另一轮 groupby @last,join结果

s=(~df.Status).groupby(level=['ID','Episode']).cumsum().reset_index()

s[df.Status.values].groupby(['ID','Episode','Status'])['Date'].agg(['first','last']).groupby(level=[0,1]).agg(','.join)
Out[104]: 
                             first                   last
ID  Episode                                              
bar 1                   2019-03-04             2019-03-04
    2        2019-03-05,2019-03-08  2019-03-06,2019-03-08
foo 1                   2019-02-02             2019-02-03
    2                   2019-02-05             2019-02-06
    3                   2019-02-09             2019-02-10

【讨论】:

  • 谢谢。至少不是一个让我无法理解的简单解决方案。现在我只需要明白答案。
  • @JoãoColaço 是的,如果您有任何问题,请告诉我
  • 我对这个答案的理解是,布尔值上有一个 cumsum,它具有将 [True, False] 映射到 +1、+0 的效果。这意味着例如 [False, False, True, True, False] 被映射到 [0, 0, 1, 2, 2]。之后使用聚合函数“first”和“last”,获取数字出现在映射系列中的第一次和最后一次。在示例 [0, 0, 1, 2 , 2] 中,数字 0 第一次出现在 0 中,数字 1 第一次出现在索引 2 中,依此类推。最后再次使用带有 .join 的聚合函数。一个有趣但相当复杂的答案!
  • 关闭。对 False 值进行累加,因此 True 值将始终具有相同的数字 (~df.Status)。在下一行中,此 series/df 仅针对具有真值 s[df.Status.values] 的行进行过滤。在此之后,对于 Status 中的每个 True 连续,该系列将具有不同的值。这将启用围绕该值进行分组,获取第一个和最后一个日期,最后按剧集分组并将结果汇​​总在一行中。
【解决方案2】:

您还可以使用 pandas.Series.shift 将您的 Status 列移动一位。

df['prev_Status'] = df['Status'].shift(1)
df['next_Status'] = df['Status'].shift(-1)

                    Status  prev_Status next_Status
Date            
foo 1   2019-02-01  False   NaN     True
        2019-02-02  True    False   True
        2019-02-03  True    True    False
        2019-02-04  False   True    True
2       2019-02-05  True    False   True
        2019-02-06  True    True    False

切换后,您可以在打开True 时按预期查询

df.query('prev_Status=="False"').query('Status=="True"').groupby(level=[0,1]).Date.agg(','.join)

bar  1    2019-03-04
     2    2019-03-08
foo  1    2019-02-02
     2    2019-02-05
     3    2019-02-09
Name: Date, dtype: object

或何时关闭

df.query('Status=="True"').query('next_Status=="False"').groupby(level=[0,1]).Date.agg(','.join)

bar  2    2019-03-06,2019-03-08
foo  1               2019-02-03
     2               2019-02-06
     3               2019-02-10
Name: Date, dtype: object

有人可能会争辩说,这比另一个(非常好的)答案效率低,但更容易理解

【讨论】:

    猜你喜欢
    • 2020-02-19
    • 2016-10-29
    • 1970-01-01
    • 2023-04-02
    • 2019-05-11
    • 2018-08-12
    • 1970-01-01
    相关资源
    最近更新 更多