【问题标题】:Count unique IDs for each group within x days计算 x 天内每个组的唯一 ID
【发布时间】:2021-03-14 23:22:35
【问题描述】:

这是我已在此处发布的问题的后续问题:Count occurrence of IDs within the last x days in R

我正在尝试进行另一个滚动计数。我有以下数据:

date = c("2014-04-01", "2014-04-12", "2014-04-07", "2014-05-03", "2014-04-14", "2014-05-04", "2014-03-31", "2014-04-18", "2014-04-23", "2014-04-01")
group = c("G","G","F","G","E","E","H","H","H","A")
ID = c(2, 3, 4, 2, 3, 1, 2, 4, 2, 1)
    group       date ID
 1:     G 2014-04-01  2
 2:     G 2014-04-12  3
 3:     F 2014-04-07  4
 4:     G 2014-05-03  2
 5:     E 2014-04-14  3
 6:     E 2014-05-04  1
 7:     H 2014-03-31  2
 8:     H 2014-04-18  4
 9:     H 2014-04-23  2
10:     A 2014-04-01  1

对于每个group,我想计算当前date 在过去30 天内唯一ID 的数量。所需的计数列如下所示:

    group       date ID  count
 1:     G 2014-04-01  2      1
 2:     G 2014-04-12  3      2
 3:     F 2014-04-07  4      1
 4:     G 2014-05-03  1      2
 5:     E 2014-04-14  3      1
 6:     E 2014-05-04  1      2
 7:     H 2014-03-31  2      1
 8:     H 2014-04-18  4      2
 9:     H 2014-04-23  2      3
10:     A 2014-04-01  1      1

在我之前的帖子中,@ThomasIsCoding 提供了一个解决方案。我尝试通过执行以下操作来修改他的代码以执行我现在尝试执行的任务:

dt[date <= first(date) + 30, date := as.Date(date)][, count := uniqueN(ID), group]
    group       date ID count
 1:     G 2014-04-01  2     2
 2:     G 2014-04-12  3     2
 3:     F 2014-04-07  4     1
 4:     G 2014-05-03  2     2
 5:     E 2014-04-14  3     2
 6:     E 2014-05-04  1     2
 7:     H 2014-03-31  2     2
 8:     H 2014-04-18  4     2
 9:     H 2014-04-23  2     2
10:     A 2014-04-01  1     1

但它似乎没有考虑时间范围条件。非常感谢任何建议!

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    使用非等连接的选项:

    DT[, onemthago := date - 30L]    
    DT[, count := 
        DT[.SD, on=.(group, date>=onemthago, date<=date),
            by=.EACHI, length(unique(ID))]$V1
    ]
    

    输出:

        group       date ID  onemthago count
     1:     G 2014-04-01  2 2014-03-02     1
     2:     G 2014-04-12  3 2014-03-13     2
     3:     F 2014-04-07  4 2014-03-08     1
     4:     G 2014-05-03  2 2014-04-03     2
     5:     E 2014-04-14  3 2014-03-15     1
     6:     E 2014-05-04  1 2014-04-04     2
     7:     H 2014-03-31  2 2014-03-01     1
     8:     H 2014-04-18  4 2014-03-19     2
     9:     H 2014-04-23  2 2014-03-24     2
    10:     A 2014-04-01  1 2014-03-02     1
    

    数据:

    date = as.Date(c("2014-04-01", "2014-04-12", "2014-04-07", "2014-05-03", "2014-04-14", "2014-05-04", "2014-03-31", "2014-04-18", "2014-04-23", "2014-04-01"))
    group = c("G","G","F","G","E","E","H","H","H","A")
    ID = c(2, 3, 4, 2, 3, 1, 2, 4, 2, 1)
    library(data.table)
    DT <- data.table(group, date, ID)
    

    编辑以解决对多个回溯期的评论。您可以尝试以下方法:

    for (x in c(30L, 90L)) {
        DT[, daysago := date - x]
        
        DT[, paste0("count", x) := 
            .SD[.SD, on=.(group, date>=daysago, date<=date),
                by=.EACHI, length(unique(ID))]$V1
        ][]
    }
    DT
    

    【讨论】:

      【解决方案2】:

      如果我正确理解了您的问题,tidyverse 中的另一种方法是:

      library(tidyverse)
      
      tb <- dplyr::tibble(date = c("2014-04-01", "2014-04-12", "2014-04-07", "2014-05-03", "2014-04-14", "2014-05-04", "2014-03-31", "2014-04-18", "2014-04-23", "2014-04-01"),
                          group = c("G","G","F","G","E","E","H","H","H","A"),
                          ID = c(2, 3, 4, 2, 3, 1, 2, 4, 2, 1))
      
      tb %>% 
        dplyr::group_by(group) %>% 
        dplyr::mutate(as.numeric(difftime(Sys.Date(), date)) < 31) %>% 
        dplyr::distinct(ID) %>% 
        dplyr::count(group) %>% 
        dplyr::right_join(tb) %>% 
        dplyr::select(group, date, ID, Count = n)
      
         group date          ID Count
          <chr> <chr>      <dbl> <int>
       1 A     2014-04-01     1     1
       2 E     2014-04-14     3     2
       3 E     2014-05-04     1     2
       4 F     2014-04-07     4     1
       5 G     2014-04-01     2     2
       6 G     2014-04-12     3     2
       7 G     2014-05-03     2     2
       8 H     2014-03-31     2     2
       9 H     2014-04-18     4     2
      10 H     2014-04-23     2     2
      

      对于滚动窗口类型的函数,这应该是一个解决方案:

      tb %>% 
        dplyr::full_join(tb, by = "group") %>% 
        dplyr::filter(as.numeric(difftime(as.Date(date.x), as.Date(date.y), units = "days")) >= 0 & as.numeric(difftime(date.x, date.y, units = "days")) < 31) %>% 
        dplyr::distinct(group, date.x, ID.y) %>% 
        dplyr::count(group, date.x) %>% 
        # you might want to cut the pipe here and look at the result (do not forget to delete the %>% in the line above when removing the part below
        dplyr::right_join(tb, by = c("group", "date.x" = "date")) %>% 
        dplyr::select(group, date = date.x, ID, count = n)
      
         group date          ID count
         <chr> <chr>      <dbl> <int>
       1 A     2014-04-01     1     1
       2 E     2014-04-14     3     1
       3 E     2014-05-04     1     2
       4 F     2014-04-07     4     1
       5 G     2014-04-01     2     1
       6 G     2014-04-12     3     2
       7 G     2014-05-03     2     2
       8 H     2014-03-31     2     1
       9 H     2014-04-18     4     2
      10 H     2014-04-23     2     2
      

      【讨论】:

      • 嗨@DPH,感谢您的建议。我唯一担心的是我想保持列的长度等于原始表上的行。因此,在当前日期,它会查看 30 天内发生了多少唯一 ID,并为每个组执行此操作。
      • 好的,我会相应地更改我的代码...只需加入原始数据...请一分钟
      • 您好@DPH,这与我正在寻找的解决方案非常接近,但是对于每个组的第一个日期,它的计数应该为 1,因为这是当前的第一个唯一 ID日期。例如,第 5 行的计数应该为 1,因为它只看到了一个唯一 ID。
      • @statman123 如果我理解正确,您正在寻找窗口类型的函数 - 比如从 data.frame 中的每个日期返回 30 天(不仅仅是从当前日期返回 30 天)?跨度>
      • 是的,这是正确的!抱歉,我应该说得更清楚。
      【解决方案3】:

      看看这个建议的解决方案对您的情况有多好。

      
      
      date = c("2014-04-01", "2014-04-12", "2014-04-07", "2014-05-03", "2014-04-14", "2014-05-04", "2014-03-31", "2014-04-18", "2014-04-23", "2014-04-01")
      group = c("G","G","F","G","E","E","H","H","H","A")
      ID = c(2, 3, 4, 2, 3, 1, 2, 4, 2, 1)
      
      dt <- data.table( date=as.Date(date), group, ID )
      setkey( dt, group, date )
      calc.id <- function(ID,date) {
          ## there is always going to be at least 1
          id.count <- 1
          if( length(ID) > 1 ) {
              v <- sapply( 2:length(ID), function(i) {
                  j <- date[ 1:i ] >= date[i] - 30
                  uniqueN( ID[j] )
              })
              id.count <- c( id.count, v )
          }
          return( id.count )
      }
      dt[ , count := calc.id(ID,date), by=group ]
      
      dt
      
      

      除了使用 sapply 进行滚动计算之外,我没有找到其他方法。我怀疑它会胜过上面的解决方案。

      它产生这个:

                date group ID count
       1: 2014-04-01     A  1     1
       2: 2014-04-14     E  3     1
       3: 2014-05-04     E  1     2
       4: 2014-04-07     F  4     1
       5: 2014-04-01     G  2     1
       6: 2014-04-12     G  3     2
       7: 2014-05-03     G  2     2
       8: 2014-03-31     H  2     1
       9: 2014-04-18     H  4     2
      10: 2014-04-23     H  2     2
      
      

      【讨论】:

      • 你好天狼星!谢谢回复。这里的几个问题是,在第 3 行,它说 NA,但我希望计数说 2,因为 E 组在包括当前日期在内的 30 天内有两个唯一的 IDS,它们是(ID = 3 和 ID = 1) .对于第 7 行,我希望该计数为 2,对于第 8 行,我希望该计数为 1。
      • 我更新了一条语句,用该组中的非 NA 值更新每个组。 (可能有更巧妙的方法,na.omit 可能会这样做,因为你保证在那里有一个非 NA)
      • (您当然可以按照通常的 data.table 方式链接这些语句)
      • 谢谢小天狼星!唯一的问题是第 3 行的计数应为 2。由于在当前日期前 30 天(包括当前日期),组 E 具有两个唯一 ID,即 3 和 1。第 8 行的计数应为 1,因为它只看到过该唯一 ID 一次。
      • 我从一开始就误解了你。对于具有数百万行的数据表的快速解决方案.. 选项更加有限。我会看看我能想出什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多