【问题标题】:Record Consecutive Days by Group in R在 R 中按组记录连续天数
【发布时间】:2017-04-20 09:36:48
【问题描述】:

我有一个如下的数据框:

DATE <- as.Date(c('2016-12-01', '2016-12-02', '2016-12-03', '2016-12-04', '2016-12-01', '2016-12-03', '2016-12-04', '2016-12-04' ))
Parent <- c('A','A','A','A','A','A','A','B')
Child <- c('ab', 'ab', 'ab', 'ab', 'ac','ac', 'ac','bd')
salary <- c(1000, 100, 4000, 2000,1000,3455,1234,600)
avg_child_salary <- c(500, 500, 500, 500, 300, 300, 300, 9000)
Callout <- c('HIGH', 'LOW', 'HIGH', 'HIGH', 'HIGH', 'HIGH', 'HIGH', 'LOW')
employ.data <- data.frame(DATE, Parent, Child, avg_child_salary, salary, Callout)

employ.data

        DATE Parent Child avg_child_salary salary Callout
1 2016-12-01      A    ab              500   1000    HIGH
2 2016-12-02      A    ab              500    100     LOW
3 2016-12-03      A    ab              500   4000    HIGH
4 2016-12-04      A    ab              500   2000    HIGH
5 2016-12-01      A    ac              300   1000    HIGH
6 2016-12-03      A    ac              300   3455    HIGH
7 2016-12-04      A    ac              300   1234    HIGH
8 2016-12-04      B    bd             9000    600     LOW

我过滤掉了昨天的数据2016-12-04如下:

yesterday <- as.Date(Sys.Date()-1)
df2<-filter(employ.data, DATE == yesterday)
df2

            DATE Parent Child avg_child_salary salary Callout
    4 2016-12-04      A    ab              500   2000    HIGH
    7 2016-12-04      A    ac              300   1234    HIGH
    8 2016-12-04      B    bd             9000    600     LOW

我的目标是在Callout 旁边添加一列,显示从2016-12-04HIGHLOW 的连续天数,基于Child 数据框。这就是我需要的最终输出:

            DATE Parent Child avg_child_salary salary Callout   Consec. Days with Callout
    4 2016-12-04      A    ab              500   2000    HIGH                           2
    7 2016-12-04      A    ac              300   1234    HIGH                           2
    8 2016-12-04      B    bd             9000    600     LOW                           1

谢谢!

【问题讨论】:

    标签: r join dplyr


    【解决方案1】:

    这是另一种相当混乱的方法,但我认为可以满足您的要求:

    library(dplyr)
    yesterday <- as.Date(Sys.Date()-1)
    df2 <- employ.data %>% group_by(Child) %>%
      mutate(`Consec. Days with Callout`=cumsum(rev(cumprod(rev((yesterday-DATE)==(which(DATE == yesterday)-row_number()) & Callout==Callout[DATE == yesterday]))))) %>%
      filter(DATE == yesterday)
    ##Source: local data frame [3 x 7]
    ##Groups: Child [3]
    ##
    ##        DATE Parent  Child avg_child_salary salary Callout Consec. Days with Callout
    ##      <date> <fctr> <fctr>            <dbl>  <dbl>  <fctr>                     <dbl>
    ##1 2016-12-04      A     ab              500   2000    HIGH                         2
    ##2 2016-12-04      A     ac              300   1234    HIGH                         2
    ##3 2016-12-04      B     bd             9000    600     LOW                         1
    

    注意事项:

    1. 如果CalloutyesterdayCallout 相同,并且如果与yesterday 行的行距为与日期的天数相同。这给出了Cond 列,如下所示:

      Source: local data frame [8 x 7]
      Groups: Child [3]
      
              DATE Parent  Child avg_child_salary salary Callout  Cond
            <date> <fctr> <fctr>            <dbl>  <dbl>  <fctr> <lgl>
      1 2016-12-01      A     ab              500   1000    HIGH  TRUE
      2 2016-12-02      A     ab              500    100     LOW FALSE
      3 2016-12-03      A     ab              500   4000    HIGH  TRUE
      4 2016-12-04      A     ab              500   2000    HIGH  TRUE
      5 2016-12-01      A     ac              300   1000    HIGH FALSE
      6 2016-12-03      A     ac              300   3455    HIGH  TRUE
      7 2016-12-04      A     ac              300   1234    HIGH  TRUE
      8 2016-12-04      B     bd             9000    600     LOW  TRUE
      
    2. 鉴于此,我们希望从yesterday 的行(按Child 分组)倒数连续的TRUE 的数量。为此,我们可以使用rev 反转向量,执行cumprod,一旦遇到FALSE,它将从1 切换到0,使用rev 再次反转向量, 最后做cumsum 累积连续天数。这样做会得到以下结果,其中 Consec. Days with Callout 列被解释为之前连续天数,Calloutyesterday 相同:

      Source: local data frame [8 x 7]
      Groups: Child [3]
      
              DATE Parent  Child avg_child_salary salary Callout Consec. Days with Callout
            <date> <fctr> <fctr>            <dbl>  <dbl>  <fctr>                     <dbl>
      1 2016-12-01      A     ab              500   1000    HIGH                         0
      2 2016-12-02      A     ab              500    100     LOW                         0
      3 2016-12-03      A     ab              500   4000    HIGH                         1
      4 2016-12-04      A     ab              500   2000    HIGH                         2
      5 2016-12-01      A     ac              300   1000    HIGH                         0
      6 2016-12-03      A     ac              300   3455    HIGH                         1
      7 2016-12-04      A     ac              300   1234    HIGH                         2
      8 2016-12-04      B     bd             9000    600     LOW                         1
      
    3. 最后,像生成最终结果一样执行filter

    【讨论】:

    • 您对这个答案有疑问吗?如果是这样,请在此处发表评论。否则,我不会直接收到。
    • 我相信您遇到了该错误,因为您有一个没有与 yesterday 匹配的日期的组。这是真的吗?
    【解决方案2】:

    试试这个我的男人

    library(lubridate)
    
    df3 <- df2 %>% 
           group_by(child, callout) %>%                          
           mutate(DATE = ymd(DATE), 
                  consecutive_day_flag = if_else(DATE == (lag(DATE) + days(1)), 1, 0),
                  how_many = sum(consecutive_day_flag))
    

    【讨论】:

    • 这真的很好,谢谢。唯一的就是Consec。标注的日子与我上面的数字不同。我猜这与不将 2016-12-04 包括为 1 天有关。它必须引用employ.data 数据框。让我知道这是否有意义,并感谢您的帮助!
    • 我很抱歉没有在问题中说清楚,只是修改了问题。 @Noobie
    • 连续你的意思是只有第二天是前一天+一天的日子?说星期六在星期五之后还是星期一在星期五之后?还是您只关心独特天数?
    • 表示周五之后的周六是连续的一天,但周五之后的周日不是。例如,第 5-7 行都标记为“HIGH”,但不是连续的天,因为我们跳过了 2016-12-02。所以孩子ac 的连续天数应该是 2 而不是 3。
    • 所以脚本需要引用employ.data数据框。因为连续的天数就是以此为基础的。然后我需要在df2中找到连续天数。
    猜你喜欢
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-18
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多