Python 获取多重索引系列级别内序列的第一个和最后一个元素
我有一个系列,它的状态可以是真的,也可以是假的。它有一个多索引,第一级为ID,第二级为每个ID中的一集,第三级为记录状态的日期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 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,序列将具有不同的值。这将允许围绕这些值进行分组,获取第一个和最后一个日期,最后按事件分组,并仅在一行中聚合结果。