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

问题描述 投票:0回答:3

这里有一个这样的时间序列数据,称之为 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

我想获取连续'Value'为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
python pandas apply
3个回答
49
投票

这样应该可以了

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)

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

0
投票
def function1(dd1:pd.DataFrame):
    col1=dd1.Value
    col2=(~(col1.eq(1)&col1.diff().eq(0))).cumsum()
    dd2=dd1.assign(col2=col2).sql().aggregate(aggr_expr="no,min(date) BeginDate,max(date) EndDate,count(1) Consecutive",group_expr="no,col2").filter("Consecutive>1")
    return dd2.to_df()

df1.groupby(['No'],as_index=False).apply(function1).reset_index(drop=1)

:

┌───────┬────────┬────────────┬────────────┬─────────────┐
│ index │   No   │ BeginDate  │  EndDate   │ Consecutive │
│ int64 │ int64  │  varchar   │  varchar   │    int64    │
├───────┼────────┼────────────┼────────────┼─────────────┤
│     0 │ 600000 │ 1999-11-19 │ 1999-11-24 │           4 │
│     1 │ 600000 │ 1999-11-10 │ 1999-11-17 │           6 │
│     2 │ 600001 │ 1999-11-26 │ 1999-11-29 │           2 │
└───────┴────────┴────────────┴────────────┴─────────────┘
© www.soinside.com 2019 - 2024. All rights reserved.