【问题标题】:Count consecutive values and average/min/max time for each group of values计算每组值的连续值和平均/最小/最大时间
【发布时间】:2021-09-25 23:27:52
【问题描述】:

我有一个带有日期时间索引的 pandas 数据框以及多列 1 和 0。我希望将那些 1 和 0 聚集在一起,以找出一个序列中有多少个。然后,我希望使用日期时间索引来确定每列中团块的最小、平均和最大时间。我只需要计算 1,因为在这种情况下,它们本质上是“开启”值。如果只有一个 1,那么从那个 1 到下一行的时间就是时间范围。

到目前为止,我已经从这篇帖子 Counting cons values and adding them 看到了第一部分以这种方式完成的

y * (y.groupby((y != y.shift()).cumsum()).cumcount() + 1)

索引为“年-月-日时:分:秒”

Dataframe 的一个例子如下。

                                   col1     col2
datetime
2021-05-24 00:09:22                    1       0 
2021-05-24 00:09:24                    1       0  
2021-05-24 00:09:25                    0       1 
2021-05-24 00:09:26                    1       0 
2021-05-24 00:09:27                    0       0

在几秒钟或几分钟内为一列提供这样的所需输出。输出必须使用日期时间索引,而不是仅仅计算连续值并乘以时间,因为日期时间不一致。

col1              col2
min  1               1
max  3               1
mean 2               1

【问题讨论】:

  • 您能解释一下您的预期输出吗?我明白为什么 max 是 2 秒,但是你如何计算一个只包含一行的块的时间?您是否考虑 0 的运行和 1 的运行?也许您可以稍微扩展示例数据框以使其更清晰,并为 col2 提供预期的输出。
  • 刚刚添加了附加信息,希望足以解决信息不足的问题。

标签: python pandas time-series


【解决方案1】:

您想要的确切操作对我来说并不完全清楚,但如果我正确理解您想要统计 1 的持续时间,您可以使用以下方法:

首先,确保索引使用日期时间类型:

df.index = pd.to_datetime(df.index)

然后我计算几个标识符:

  1. 每个拉伸的第一个元素 (first_stretch)
  2. 每个拉伸的最后一个元素 (last_stretch)
  3. 拉伸组 (stretch_group)
  4. 与第一个值 (timedelta) 的时间差(以秒为单位)
  5. 连续行之间的时间差 (time_diff)
  6. 每次拉伸的累计时间(以秒为单位) (cum_diff)
df['first_stretch'] = df['col1']&df['col1'].shift(1).fillna(0).eq(0)
df['last_stretch']  = (df['col1']-df['col1'].shift(-1)).eq(1)
df['stretch_group'] = df['first_stretch'].cumsum().mask(~df['col1'].astype(bool))
df['timedelta'] = (df.index-df.index[0]).total_seconds().astype(int)
df['timediff'] = df['timedelta'].diff(1).fillna(0).astype(int)
df['cum_diff'] = df.groupby('stretch_group')['timediff'].cumsum()*df['col1']

                     col1  col2  first_stretch  last_stretch  stretch_group  timedelta  timediff  cum_diff
datetime                                                                                                  
2021-05-24 00:09:22     1     0           True         False            1.0          0         0         0
2021-05-24 00:09:24     1     0          False          True            1.0          2         2         2
2021-05-24 00:09:25     0     1          False         False            NaN          3         1         0
2021-05-24 00:09:26     1     0           True          True            2.0          4         1         1
2021-05-24 00:09:27     0     0          False         False            NaN          5         1         0

也许您不需要所有这些,但这使得进行各种计算变得容易。例如,如果您想获取每个拉伸的最小/最大/平均持续时间:

>>> df[df.last_stretch]['timediff'].agg(['mean', 'min', 'max'])
mean    1.5
min     1.0
max     2.0

这些值并不完全相同,因此请说明您的时间间隔的确切界限。

【讨论】:

  • 我已经尝试了好几天了,这正是我所需要的。很抱歉没有澄清,但你在阅读和回答问题方面做得很好。非常感谢。
【解决方案2】:

你可以试试这个:

def count_secs(ser):
    return (ser.index[-1] - ser.index[0]).seconds + 1

def min_max_mean(col):
    if 1 not in col.values:
        return 0, 0, 0
    groups = (col != col.shift(1))[col.eq(1)].cumsum()
    counts = groups.groupby(groups.values).apply(count_secs)
    return counts.min(), counts.max(), counts.mean()

df = df.apply(min_max_mean, axis='index')
df.index = ['min', 'max', 'mean']

df 的结果

                     col1  col2
datetime                       
2021-05-24 00:09:22     1     0
2021-05-24 00:09:24     1     0
2021-05-24 00:09:25     0     1
2021-05-24 00:09:26     1     0
2021-05-24 00:09:27     0     0

      col1  col2
min    1.0   1.0
max    3.0   1.0
mean   2.0   1.0

编辑:我对您的问题的解释是您想要考虑索引中缺少的秒数(您的示例输出表明这就是您要查找的内容)。如果不是这种情况 - 请参阅 @mozway 的答案 - 那么没有 count_secs 函数的更简单的版本就足够了:

def min_max_mean(col):
    if 1 not in col.values:
        return 0, 0, 0
    groups = (col != col.shift(1))[col.eq(1)].cumsum()
    counts = groups.groupby(groups.values).count()
    return counts.min(), counts.max(), counts.mean()

df = df.apply(min_max_mean, axis='index')
df.index = ['min', 'max', 'mean']

结果:

      col1  col2
min    1.0   1.0
max    2.0   1.0
mean   1.5   1.0

【讨论】:

  • 谢谢。这非常有效,特别是如果我以后有更多的列。
猜你喜欢
  • 1970-01-01
  • 2016-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多