【问题标题】:using dplyr to calculate consecutive days with a particular value使用 dplyr 计算具有特定值的连续天数
【发布时间】:2019-05-13 14:42:01
【问题描述】:

我正在尝试计算冬季严重程度的指数,该指数的组成部分之一需要计算在该特定日期之前(包括该特定日期)

Day 1 = 2 degrees C  
Day 2 = -2 degrees C  
Day 3 = -5 degrees C

所以我尝试计算的值(称为 tempdays)在第 1 天等于 0;第 2 天 1 次;第 3 天 2 个。

这是一个显示数据外观的示例:

dat <- tibble(
  date = seq(as.Date('2010-01-01'), as.Date('2010-01-10'), 1),
  temp = c(4.2, 3.35, -0.6, -0.25, 0.8, 0.8, -2.5, -5.25, -0.5, 3.35)
)
dat

 date        temp
   <date>     <dbl>
 1 2010-01-01  4.2 
 2 2010-01-02  3.35
 3 2010-01-03 -0.6 
 4 2010-01-04 -0.25
 5 2010-01-05  0.8 
 6 2010-01-06  0.8 
 7 2010-01-07 -2.5 
 8 2010-01-08 -5.25
 9 2010-01-09 -0.5 
10 2010-01-10  3.35

这是另一个以小于零的临时值开始的数据集,因为这似乎会导致问题:

dat2 <- tibble(
  date = seq(as.Date('2010-01-01'), as.Date('2010-01-10'), 1),
  temp = c(-1.95, -1.1, -2.8, -6.7, 1.4, 4.45, 6.1, 4.7, -1.7, -3.9)
)
dat2

所以 dat2 应该是这样的:

date        temp tempdays
   <date>     <dbl>    <dbl>
 1 2010-01-01 -1.95        1
 2 2010-01-02 -1.1         2
 3 2010-01-03 -2.8         3
 4 2010-01-04 -6.7         4
 5 2010-01-05  1.4         0
 6 2010-01-06  4.45        0
 7 2010-01-07  6.1         0
 8 2010-01-08  4.7         0
 9 2010-01-09 -1.7         1
10 2010-01-10 -3.9         2

我猜lag() 可以用来做这个吗?

【问题讨论】:

标签: r dplyr lubridate


【解决方案1】:

您可以使用cumsum 创建一个分组变量,然后使用row_number 生成温度小于0 的连续天数。

library(dplyr)

dat %>%
  group_by(group = cumsum(temp > 0)) %>%
  mutate(tempdays = row_number() - 1) %>%
  ungroup() %>%
  select(-group)


#    date      temp tempdays
#   <date>     <dbl>    <dbl>
# 1 2010-01-01  4.2         0
# 2 2010-01-02  3.35        0
# 3 2010-01-03 -0.6         1
# 4 2010-01-04 -0.25        2
# 5 2010-01-05  0.8         0
# 6 2010-01-06  0.8         0
# 7 2010-01-07 -2.5         1
# 8 2010-01-08 -5.25        2
# 9 2010-01-09 -0.5         3
#10 2010-01-10  3.35        0

并使用 ave 的基本 R

with(dat, ave(temp, cumsum(temp > 0), FUN = seq_along) - 1)

编辑

如果第一组为负数,这将无法按预期工作。这是使用rle 的更新版本,它适用于dat 以及dat2

dat2 %>%
  mutate(tempdays = with(rle(temp < 0), rep(values, lengths))) %>%
  group_by(group = cumsum(temp > 0)) %>%
  mutate(tempdays = cumsum(tempdays)) %>%
  ungroup() %>%
  select(-group)


#      date    temp   tempdays
#     <date>   <dbl>    <int>
# 1 2010-01-01 -1.95        1
# 2 2010-01-02 -1.1         2
# 3 2010-01-03 -2.8         3
# 4 2010-01-04 -6.7         4
# 5 2010-01-05  1.4         0
# 6 2010-01-06  4.45        0
# 7 2010-01-07  6.1         0
# 8 2010-01-08  4.7         0
# 9 2010-01-09 -1.7         1
#10 2010-01-10 -3.9         2

【讨论】:

  • 如果可以,我将添加一个稍微不同的示例。出于某种原因,如果第一个日期的 temp 值小于 0,那么您的解决方案会为第一个日期创建一个等于 0 的 tempdays 而不是一个
【解决方案2】:

我们可以使用data.table

library(data.table)
setDT(dat)[, tempdays := seq_len(.N) -1 , cumsum(temp > 0)]
dat
#          date  temp tempdays
# 1: 2010-01-01  4.20        0
# 2: 2010-01-02  3.35        0
# 3: 2010-01-03 -0.60        1
# 4: 2010-01-04 -0.25        2
# 5: 2010-01-05  0.80        0
# 6: 2010-01-06  0.80        0
# 7: 2010-01-07 -2.50        1
# 8: 2010-01-08 -5.25        2
# 9: 2010-01-09 -0.50        3
#10: 2010-01-10  3.35        0

【讨论】:

    猜你喜欢
    • 2017-02-26
    • 2021-11-07
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    相关资源
    最近更新 更多