【问题标题】:dplyr reset counter when the threshold is reached达到阈值时 dplyr 重置计数器
【发布时间】:2020-12-28 05:13:08
【问题描述】:

我有以下tibbletest

  datetime                volume
  <dttm>                   <dbl>
  2020-08-25 09:30:00.000      0
  2020-08-25 09:30:12.000    107
  2020-08-25 09:30:50.000    221
  2020-08-25 09:30:50.000    132
  2020-08-25 09:30:50.000    148
  2020-08-25 09:30:50.000    100
  2020-08-25 09:30:50.000    100
  2020-08-25 09:30:58.000    100
  2020-08-25 09:31:56.000    157
  2020-08-25 09:32:36.000    288
  2020-08-25 09:32:36.000    100
  2020-08-25 09:33:10.000    235
  2020-08-25 09:33:23.000    182
  2020-08-25 09:33:44.000    218
  2020-08-25 09:33:44.000    179
  2020-08-25 09:34:18.000    318
  2020-08-25 09:34:27.000    101
  2020-08-25 09:34:27.000    157
  2020-08-25 09:34:27.000    200
  2020-08-25 09:34:27.000    114

当达到volume 的阈值时,我想计算累积时间差(甚至只是时间戳相同的行数)。一旦达到/超过阈值,我将计数器重置为 0,并从该点开始再次累积。

例如,如果我的threshold 是300,我从1 行累积到3 行,我会得到0+107+221=328,我现在会选择:

  • 保留此行的时间戳,
  • 计算行1到行3的时间差,
  • 或计算行数直到达到阈值

以上任何一项都可以达到目的,最好的选择是保留时间戳。

下一步是重置计数器(目前保持在328)并从4行重新开始计数;从4 行到7 行我累积148+100+100=348,我会再次保留时间戳(例如)。然后我会再次重置计数器并继续前进。

我试图通过dplyr 或通常在tidyverse 中执行此操作,但是我无法提出合理的解决方案。我认为没有办法仅通过管道与 dplyr 一起完成此操作。

我想我可以通过for-loop 解决问题,但这是我最后的选择。对我来说困难的部分是重置计数器并重新开始计数。

【问题讨论】:

  • 请添加您想要的输出。
  • @tmfmnk 抱歉,我无法真正想出理想的输出,因为我不确定最终输出是什么。更重要的是,我认为如果有替代方案会更容易解决,因为我认为这并不容易。我希望我的描述足够清楚,如果没有,请告诉我。

标签: r dplyr tidyr purrr


【解决方案1】:

dplyrpurrr 的一种可能性可能是:

df %>%
 group_by(group_id = cumsum(c(0, diff(accumulate(volume, ~ if_else(.x >= 300, .y, .x + .y))) < 0))) %>%
 summarise(timestamp_first = first(datetime),
           timestamp_last = last(datetime),
           time_diff = last(datetime) - first(datetime),
           n_rows = n(),
           volume_sum = sum(volume))

  group_id timestamp_first     timestamp_last      time_diff n_rows volume_sum
     <dbl> <dttm>              <dttm>              <drtn>     <int>      <int>
1        0 2020-08-25 09:30:00 2020-08-25 09:30:50 50 secs        3        328
2        1 2020-08-25 09:30:50 2020-08-25 09:30:50  0 secs        3        380
3        2 2020-08-25 09:30:50 2020-08-25 09:31:56 66 secs        3        357
4        3 2020-08-25 09:32:36 2020-08-25 09:32:36  0 secs        2        388
5        4 2020-08-25 09:33:10 2020-08-25 09:33:23 13 secs        2        417
6        5 2020-08-25 09:33:44 2020-08-25 09:33:44  0 secs        2        397
7        6 2020-08-25 09:34:18 2020-08-25 09:34:18  0 secs        1        318
8        7 2020-08-25 09:34:27 2020-08-25 09:34:27  0 secs        3        458
9        8 2020-08-25 09:34:27 2020-08-25 09:34:27  0 secs        1        114

【讨论】:

  • uhh....我现在很难不接受您的回答,因为它涵盖了所有替代方案呵呵;分组不是很直观,但我想我会一次咬一口。我今天学到了新技巧,谢谢。
【解决方案2】:

这可能会让你继续前进。它利用了MESS-package,尤其是天才cumsumbinning-function。

样本数据

library( data.table )
library( MESS )
test <- data.table::fread( "datetime                volume
2020-08-25T09:30:00.000      0
2020-08-25T09:30:12.000    107
2020-08-25T09:30:50.000    221
2020-08-25T09:30:50.000    132
2020-08-25T09:30:50.000    148
2020-08-25T09:30:50.000    100
2020-08-25T09:30:50.000    100
2020-08-25T09:30:58.000    100
2020-08-25T09:31:56.000    157
2020-08-25T09:32:36.000    288
2020-08-25T09:32:36.000    100
2020-08-25T09:33:10.000    235
2020-08-25T09:33:23.000    182
2020-08-25T09:33:44.000    218
2020-08-25T09:33:44.000    179
2020-08-25T09:34:18.000    318
2020-08-25T09:34:27.000    101
2020-08-25T09:34:27.000    157
2020-08-25T09:34:27.000    200
2020-08-25T09:34:27.000    114")

test[, datetime := as.POSIXct( datetime, format = "%Y-%m-%dT%H:%M:%OS") ]

代码

采用data.table 语法,但可以轻松集成到任何 tidyverse 或 baseR 解决方案中

#create groups based on cumsum with threshold of 300
test[, group_id := MESS::cumsumbinning( volume, threshold = 300, cutwhenpassed = TRUE )]

#                datetime volume group_id
#  1: 2020-08-25 09:30:00      0        1
#  2: 2020-08-25 09:30:12    107        1
#  3: 2020-08-25 09:30:50    221        1
#  4: 2020-08-25 09:30:50    132        2
#  5: 2020-08-25 09:30:50    148        2
#  6: 2020-08-25 09:30:50    100        2
#  7: 2020-08-25 09:30:50    100        3
#  8: 2020-08-25 09:30:58    100        3
#  9: 2020-08-25 09:31:56    157        3
# 10: 2020-08-25 09:32:36    288        4
# 11: 2020-08-25 09:32:36    100        4
# 12: 2020-08-25 09:33:10    235        5
# 13: 2020-08-25 09:33:23    182        5
# 14: 2020-08-25 09:33:44    218        6
# 15: 2020-08-25 09:33:44    179        6
# 16: 2020-08-25 09:34:18    318        7
# 17: 2020-08-25 09:34:27    101        8
# 18: 2020-08-25 09:34:27    157        8
# 19: 2020-08-25 09:34:27    200        8
# 20: 2020-08-25 09:34:27    114        9

现在分组已经完成,总结应该很容易了..

【讨论】:

  • 感谢您的出色回答,这个cumsumbinning 确实是天才,它从代码中所做的事情非常直观。是的,在上面得到我想要的只是平常的工作。在您的答案和 tmfmnk 之间进行选择对我来说是真正的问题!
猜你喜欢
  • 1970-01-01
  • 2018-07-04
  • 2021-03-26
  • 2023-03-15
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 2018-07-12
  • 2016-04-04
相关资源
最近更新 更多