如何使用pandas查找时间序列中连续相同的数据

32

这里有一组时间序列数据,假设为df:

      'No'       'Date'       'Value'
0     600000     1999-11-10    1
1     600000     1999-11-11    1
2     600000     1999-11-12    1
3     600000     1999-11-15    1
4     600000     1999-11-16    1
5     600000     1999-11-17    1
6     600000     1999-11-18    0
7     600000     1999-11-19    1
8     600000     1999-11-22    1
9     600000     1999-11-23    1
10    600000     1999-11-24    1
11    600000     1999-11-25    0
12    600001     1999-11-26    1
13    600001     1999-11-29    1
14    600001     1999-11-30    0

我想获取连续的“值”为1的日期范围,那么我该如何得到以下最终结果:

   'No'     'BeginDate'    'EndDate'   'Consecutive'
0 600000    1999-11-10    1999-11-17    6
1 600000    1999-11-19    1999-11-24    4
2 600001    1999-11-26    1999-11-29    2

嗨,acushner:你想知道什么? - figo
很失望,没有人回答。 - figo
6
这里是基本工具,其余的你可以自己解决:在“No”列上使用groupby,然后在每个组上执行df.Value - df.Value.shift(1),看看何时它们不等于零。 - acushner
相关问题:https://dev59.com/3lcO5IYBdhLWcg3wZQpH - Anton Tarasenko
相关问题:https://dev59.com/QVkR5IYBdhLWcg3w0QRL - Anton Tarasenko
运行长度编码 - Xpector
2个回答

47

这应该可以做到

df['value_grp'] = (df.Values.diff(1) != 0).astype('int').cumsum()

每当Value更改时,value_grp将增加一次。在下面,您可以提取组结果

pd.DataFrame({'BeginDate' : df.groupby('value_grp').Date.first(), 
              'EndDate' : df.groupby('value_grp').Date.last(),
              'Consecutive' : df.groupby('value_grp').size(), 
              'No' : df.groupby('value_grp').No.first()}).reset_index(drop=True)

嗨,user1827356,感谢您的快速回答,但结果与我想要的不同,您可以在您的回答下面看到我列出的结果。 - figo
@figo,我的错。在value_grp计算中有一个打字错误。你能重新检查一下吗?你可以过滤Consecutive > 1来得到你想要的答案。 - user1827356
请注意,如果 df.Values 不是数字,您仍然可以执行 (df.Values != df.Values.shift()).cumsum()(不需要 .astype(int))。 - BallpointBen
值得注意的是,在那里您实际上并不需要“astype(int)” - pandas完全可以对布尔值求和。 - MTKnife

5

这里有一个替代方案:

rslt = (df.assign(Consecutive=df.Value
                                .groupby((df.Value != df.Value.shift())
                                         .cumsum())
                                .transform('size'))
          .query('Consecutive > 1')
          .groupby('Consecutive')
          .agg({'No':{'No':'first'}, 'Date': {'BeginDate':'first', 'EndDate':'last'}})
          .reset_index()
)
rslt.columns = [t[1] if t[1] else t[0] for t in rslt.columns]

演示:

In [225]: %paste
rslt = (df.assign(Consecutive=df.Value
                                .groupby((df.Value != df.Value.shift())
                                         .cumsum())
                                .transform('size'))
          .query('Consecutive > 1')
          .groupby('Consecutive')
          .agg({'No':{'No':'first'}, 'Date': {'BeginDate':'first', 'EndDate':'last'}})
          .reset_index()
)
rslt.columns = [t[1] if t[1] else t[0] for t in rslt.columns]
## -- End pasted text --

In [226]: rslt
Out[226]:
   Consecutive  BeginDate    EndDate      No
0            2 1999-11-26 1999-11-29  600001
1            4 1999-11-19 1999-11-24  600000
2            6 1999-11-10 1999-11-17  600000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接