【问题标题】:How can you determine the number of events that have occurred over specified number of days using dplyr?如何使用 dplyr 确定在指定天数内发生的事件数?
【发布时间】:2020-08-30 06:11:58
【问题描述】:

我有一个包含三列的小标题:

  1. runner - 代表跑步者姓名的字符串
  2. race - 表示比赛次数的数值
  3. date - 比赛日期

我想添加第四列 last45d,它表示与当前行日期相比,过去 45 天内进行的比赛的数量。我的代表包括样本数据和我尝试生成新行(我得到所有 NA)。

代表:

library(tidyverse)
library(lubridate)
library(reprex)

df<-tibble(runner=c("D.Wottle","D.Wottle","D.Wottle","D.Wottle","D.Wottle","D.Wottle","C.Hottle","C.Hottle","C.Hottle","C.Hottle","C.Hottle","C.Hottle","JJ.Watt","JJ.Watt","JJ.Watt","JJ.Watt","JJ.Watt","JJ.Watt"),
           race=c(6,5,4,3,2,1,6,5,4,3,2,1,6,5,4,3,2,1),
           date=c(ymd('20170625'),ymd('20170524'),ymd('20170420'),ymd('20170329'),ymd('20170308'),ymd('20170215'),ymd('20170625'),ymd('20170524'),ymd('20170410'),ymd('20170329'),ymd('20170304'),ymd('20170215'),ymd('20170615'),ymd('20170524'),ymd('20170428'),ymd('20170329'),ymd('20170301'),ymd('20170225')),
           surface=c('T','T','D','T','D','T','T','T','D','T','D','T','T','T','D','T','D','T'),
           distance=c(1400,1400,1600,1400,1500,1400,1400,1400,1600,1400,1500,1400,1400,1400,1600,1400,1500,1400),
           finish=c(1,2,2,1,2,3,2,3,3,2,1,1,3,1,1,3,3,2)

           )

df <- df %>% 
  group_by(runner) %>% 
  mutate(last45 = map_int(date, ~ sum(between(as.numeric(difftime(.x, date, units = "days")), 1e-9, 90)))) %>%
  ungroup()
df
#> # A tibble: 18 x 7
#>    runner    race date       surface distance finish last45
#>    <chr>    <dbl> <date>     <chr>      <dbl>  <dbl>  <int>
#>  1 D.Wottle     6 2017-06-25 T           1400      1      3
#>  2 D.Wottle     5 2017-05-24 T           1400      2      3
#>  3 D.Wottle     4 2017-04-20 D           1600      2      3
#>  4 D.Wottle     3 2017-03-29 T           1400      1      2
#>  5 D.Wottle     2 2017-03-08 D           1500      2      1
#>  6 D.Wottle     1 2017-02-15 T           1400      3      0
#>  7 C.Hottle     6 2017-06-25 T           1400      2      3
#>  8 C.Hottle     5 2017-05-24 T           1400      3      3
#>  9 C.Hottle     4 2017-04-10 D           1600      3      3
#> 10 C.Hottle     3 2017-03-29 T           1400      2      2
#> 11 C.Hottle     2 2017-03-04 D           1500      1      1
#> 12 C.Hottle     1 2017-02-15 T           1400      1      0
#> 13 JJ.Watt      6 2017-06-15 T           1400      3      3
#> 14 JJ.Watt      5 2017-05-24 T           1400      1      4
#> 15 JJ.Watt      4 2017-04-28 D           1600      1      3
#> 16 JJ.Watt      3 2017-03-29 T           1400      3      2
#> 17 JJ.Watt      2 2017-03-01 D           1500      3      1
#> 18 JJ.Watt      1 2017-02-25 T           1400      2      0

reprex package (v0.3.0) 于 2020 年 5 月 13 日创建

这就是我希望最终结果的样子:

【问题讨论】:

    标签: r dplyr tidyverse


    【解决方案1】:
    df %>%
      group_by(runner) %>%
      mutate(
        last45 = map_int(date, ~ sum(between(as.numeric(difftime(.x, date, units = "days")), 1e-9, 45)))
        #                ^^^^1                                       ^^^^2
      ) %>%
      ungroup()
    # # A tibble: 6 x 4
    #   runner    race date       last45
    #   <chr>    <dbl> <date>      <int>
    # 1 D.Wottle     6 2017-06-25      1
    # 2 D.Wottle     5 2017-05-24      1
    # 3 D.Wottle     4 2017-04-20      2
    # 4 D.Wottle     3 2017-03-29      2
    # 5 D.Wottle     2 2017-03-08      1
    # 6 D.Wottle     1 2017-02-15      0
    

    注意事项:

    • date 的两个引用是不同的:“1”(在波浪号函数之外)一次转换为 .x,因此 .x 将始终是一个日期; “2”(在波浪号函数内)是日期的原始列,因此将具有与当前运行器行数一样多的值;和

    • 我使用1e-9,因为如果我使用0,则始终考虑当前日期;通过使用1e-9(或一些同样小的数字),我们得到有效的(lower,upper] 边界,而不是dplyr::between 默认的[lower,upper](两边都关闭)。

    【讨论】:

    • 谢谢。我将不得不做一些研究以了解该 mutate 函数发生了什么,但我很高兴有机会学习。这与用于执行回归分析或在 case_when 中使用的波浪号函数相同吗?
    • 什么是 1e - 9?
    • “波浪号函数”主要是简写,由 tidyverse 启用。将~ 视为function(...),其中... 因用户而异,例如function(.x) 对应mapfunction(.x, .y) 对应map21e-9 是一个非常小的数字的科学记数法,正如我在注释中讨论的那样,我使用它是因为 dplyr::between 的比较两端都“封闭”(在数学记数法意义上)。 (请随意将1e-9 替换为0.000000001。)
    • 是的,查找 &amp;,矢量化“AND”内联运算符,记录在 ?&amp; 下(该页面包括 &amp;&amp;&amp;||| 和其他一些)。例如,~ sum(between(...) &amp; dist &gt;= 1400 &amp; pos == 1L)。 (我认为这可能会起作用,尽管它会进行比严格必要的更多的比较。如果您使用“大量”数据(可能是 1M 行或更多行)执行此操作,那么可能有一些方法可以短路东西。
    • 从技术上讲,您不需要,因为它不需要与整个列进行逐行比较。但是,执行sum(map_lgl(date, ~ between(difftime(.x, date, units="days"), 1e-9, 45)) &amp; dist &gt;= 1400 &amp; pos == 1) 可能更简单(也更有效),其中 dist 和 pos 条件位于对map 的调用之外。这更有意义吗? (事后看来,这对我有用。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多