Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 获取多重索引系列级别内序列的第一个和最后一个元素_Python_Pandas_Dataframe_Series - Fatal编程技术网

Python 获取多重索引系列级别内序列的第一个和最后一个元素

Python 获取多重索引系列级别内序列的第一个和最后一个元素,python,pandas,dataframe,series,Python,Pandas,Dataframe,Series,我有一个系列,它的状态可以是真的,也可以是假的。它有一个多索引,第一级为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

我有一个系列,它的状态可以是真的,也可以是假的。它有一个多索引,第一级为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

检查使用
groupby
cumsum
创建组的内部键,下一步我们根据df中的所有
True
值进行筛选,然后使用新键执行另一轮
groupby
,并
第一次
最后一次
加入
结果

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

您还可以使用
pandas.Series.shift
状态
列逐个移动

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

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

检查您的输出栏-2个,已经更正了为什么选择了最后一行2019-03-09其他打字错误。。。我试着用一天的时间用“真”来做一个例子,但我犯了一个错误…我已经添加了一个答案谢谢。至少不是一个简单的解决方案让我无法理解。现在我只需要理解答案。@JoãoColaço yep,如果你有任何问题,请告诉我我如何理解这个答案,布尔函数上有一个
cumsum
,它在a+1,+0中具有映射[真,假]的效果。这意味着例如[False,False,True,True,False]被映射到[0,0,1,2,2]。然后使用聚合函数“first”和“last”,获取数字在映射序列中出现的第一次和最后一次。在示例[0,0,1,2,2]中,数字0在0中第一次出现,数字1在索引2中第一次出现,依此类推。最后再次使用带有.join的聚合函数。一个有趣但相当复杂的答案!接近。对假值进行累加,因此真值将始终具有相同的编号
(~df.Status)
。在下一行中,此系列/df仅针对具有真值的行进行过滤
s[df.Status.values]
。在此之后,对于状态中的每个连续True,序列将具有不同的值。这将允许围绕这些值进行分组,获取第一个和最后一个日期,最后按事件分组,并仅在一行中聚合结果。