【问题标题】:Pandas measure elapsed time when condition is true当条件为真时,熊猫测量经过的时间
【发布时间】:2017-06-15 05:52:47
【问题描述】:

我有以下数据框:

                 dt binary
2016-01-01 00:00:00  False
2016-01-01 00:00:01  False
2016-01-01 00:00:02  False
2016-01-01 00:00:03  False
2016-01-01 00:00:04   True
2016-01-01 00:00:05   True
2016-01-01 00:00:06   True
2016-01-01 00:00:07  False
2016-01-01 00:00:08  False
2016-01-01 00:00:09   True
2016-01-01 00:00:10   True

binaryTrue 时,我想总结经过的时间。我正在分享我的解决方案,它实现了它,但有些东西告诉我应该有一种更简单的方法,因为它是时间序列数据的一个非常基本的特性。请注意,数据很可能是等距的,但我不能依赖它。

df['binary_grp'] = (df.binary.diff(1) != False).astype(int).cumsum()
# Throw away False values
df = df[df.binary]
groupby = df.groupby('binary_grp')
df = pd.DataFrame({'timespan': groupby.dt.last() - groupby.dt.first()})
return df.timespan.sum().seconds / 60.0

最棘手的部分可能是第一行。它的作用是,它基本上为每个连续的块分配一个递增的数字。之后的数据如下所示:

                 dt binary  binary_grp
2016-01-01 00:00:00  False           1
2016-01-01 00:00:01  False           1
2016-01-01 00:00:02  False           1
2016-01-01 00:00:03  False           1
2016-01-01 00:00:04   True           2
2016-01-01 00:00:05   True           2
2016-01-01 00:00:06   True           2
2016-01-01 00:00:07  False           3
2016-01-01 00:00:08  False           3
2016-01-01 00:00:09   True           4
2016-01-01 00:00:10   True           4

有没有更好的方法来做到这一点?我猜这段代码是高性能的,我担心的是可读性。

【问题讨论】:

    标签: python pandas time-series


    【解决方案1】:

    在我看来,您的解决方案很好。

    另一种解决方案:

    shifted 值与ne 进行比较,得到cumsum 的分组。

    过滤后可以使用apply,通过选择iloc来区分:

    df['binary_grp'] = (df.binary.ne(df.binary.shift())).cumsum()
    
    df = df[df.binary]
    
    s = df.groupby('binary_grp')['dt'].apply(lambda x: x.iloc[-1] - x.iloc[0])
    print (s)
    binary_grp
    2   00:00:02
    4   00:00:01
    Name: dt, dtype: timedelta64[ns]
    
    all_time =  s.sum().seconds / 60.0
    print (all_time)
    0.05
    

    在您的解决方案中,如果只需要 all_time,则不需要新的 DataFrame

    groupby = df.groupby('binary_grp')
    
    s = groupby.dt.last() - groupby.dt.first()
    all_time =  s.sum().seconds / 60.0
    print (all_time)
    0.05
    

    但如果需要,可以从 Series s to_frame 创建它:

    df1 = s.to_frame('timestamp')
    print (df1)
               timestamp
    binary_grp          
    2           00:00:02
    4           00:00:01
    

    【讨论】:

      【解决方案2】:

      IIUC:

      您想要找到跨越整个系列的时间总和,其中binaryTrue

      但是,我们必须做出一些选择或假设

                          dt  binary
      0  2016-01-01 00:00:00   False
      1  2016-01-01 00:00:01   False
      2  2016-01-01 00:00:02   False
      3  2016-01-01 00:00:03   False
      4  2016-01-01 00:00:04    True # <- This where time starts
      5  2016-01-01 00:00:05    True
      6  2016-01-01 00:00:06    True
      7  2016-01-01 00:00:07   False # <- And ends here. So this would
      8  2016-01-01 00:00:08   False # be 00:00:07 - 00:00:04 or 3 seconds
      9  2016-01-01 00:00:09    True # <- Starts again
      10 2016-01-01 00:00:10    True # <- But ends here because
                                     # I don't have another Timestamp
      

      有了这些假设,我们可以使用diff、乘法和sum

      df.dt.diff().shift(-1).mul(df.binary).sum()
      
      Timedelta('0 days 00:00:04')
      

      然后我们可以将这个概念与groupby一起使用

      # Use xor and cumsum to identify change in True to False and False to True
      grps = (df.binary ^ df.binary.shift()).cumsum()
      mask = df.binary.groupby(grps).first()
      df.dt.diff().shift(-1).groupby(grps).sum()[mask]
      
      binary
      1   00:00:03
      3   00:00:01
      Name: dt, dtype: timedelta64[ns]
      

      或者不带面具

      pd.concat([df.dt.diff().shift(-1).groupby(grps).sum(), mask], axis=1)
      
                   dt  binary
      binary                 
      0      00:00:04   False
      1      00:00:03    True
      2      00:00:02   False
      3      00:00:01    True
      

      【讨论】:

        猜你喜欢
        • 2019-05-08
        • 2021-05-30
        • 1970-01-01
        • 2019-08-10
        • 2020-12-30
        • 2021-08-16
        • 2018-11-15
        • 2017-07-13
        • 2017-09-24
        相关资源
        最近更新 更多