【问题标题】:Separating non-overlapping intervals within groups and counting in R在组内分离非重叠间隔并在 R 中计数
【发布时间】:2020-07-30 02:01:10
【问题描述】:

使用 R,我拥有按 DNA 菌株(病原体的)、住院诊所和重叠的住院时间分组的住院患者数据,以确定是否可能传播。

我需要对重叠的组进行顺序编号。这看起来很简单,但有两个问题:

  1. 我在 SO 或其他地方找到的所有内容都在讨论组内的行编号。我需要一个组中的每一行都具有相同的数字,并且需要对组本身进行计数。
  2. 使用%>% group_by(strain, clinic) %>% 最初看起来很简单的任何方法都可以实现,但这并没有考虑到不重叠的时间间隔

我已经尝试了几种方法和搜索,然后最终放弃并在此处发布(我的任何尝试都不值得在此处发布事件以浪费您的时间。)以下代码是我拥有的数据的示例(have)和我想要的数据 (want)。注意菌株B,所有患者都在Clinic_1,但由于时间间隔分开,分为两组。

任何建议将不胜感激。

have <- data.frame(id=c("K01","K02","K03","K04","K05","K06","K07","K08","K09"),
                   strain=c(rep("A",4),rep("B",5)),
                   clinic=c(rep("Clinic_1",2),rep("Clinic_2",2),rep("Clinic_1",5)),
                   datein=as.Date(c("2020/01/01","2020/01/03","2020/02/03","2020/02/09","2020/02/18","2020/02/20","2020/02/21","2020/03/06","2020/03/18")),
                   dateout=as.Date(c("2020/01/05","2020/01/16","2020/02/09","2020/02/19","2020/02/27","2020/02/23","2020/02/22","2020/03/21","2020/03/22"))
                   )

want <- data.frame(have,overlap_number=c(1,1,2,2,3,3,3,4,4))

#How the final data would look
> View(want)
   id strain   clinic     datein    dateout overlap_number
1 K01      A Clinic_1 2020-01-01 2020-01-05              1
2 K02      A Clinic_1 2020-01-03 2020-01-16              1
3 K03      A Clinic_2 2020-02-03 2020-02-09              2
4 K04      A Clinic_2 2020-02-09 2020-02-19              2
5 K05      B Clinic_1 2020-02-18 2020-02-27              3
6 K06      B Clinic_1 2020-02-20 2020-02-23              3
7 K07      B Clinic_1 2020-02-21 2020-02-22              3
8 K08      B Clinic_1 2020-03-06 2020-03-21              4
9 K09      B Clinic_1 2020-03-18 2020-03-22              4

基于 Akrun 评论的替代数据集,K07 的日期略有变化:

have2 <- data.frame(id=c("K01","K02","K03","K04","K05","K06","K07","K08","K09"),
                   strain=c(rep("A",4),rep("B",5)),
                   clinic=c(rep("Clinic_1",2),rep("Clinic_2",2),rep("Clinic_1",5)),
                   datein=as.Date(c("2020/01/01","2020/01/03","2020/02/03","2020/02/09","2020/02/18","2020/02/20","2020/02/25","2020/03/06","2020/03/18")),
                   dateout=as.Date(c("2020/01/05","2020/01/16","2020/02/09","2020/02/19","2020/02/27","2020/02/23","2020/02/29","2020/03/21","2020/03/22"))
                   )

#Output:

#> have2 %>% 
#+   mutate(overlap_number = rleid(strain, clinic, 
#+                                 cumsum(datein > lag(dateout, default = #first(dateout)))))
#   id strain   clinic     datein    dateout overlap_number
#1 K01      A Clinic_1 2020-01-01 2020-01-05              1
#2 K02      A Clinic_1 2020-01-03 2020-01-16              1
#3 K03      A Clinic_2 2020-02-03 2020-02-09              2
#4 K04      A Clinic_2 2020-02-09 2020-02-19              2
#5 K05      B Clinic_1 2020-02-18 2020-02-27              3
#6 K06      B Clinic_1 2020-02-20 2020-02-23              3
#7 K07      B Clinic_1 2020-02-25 2020-02-29              4 ## treats this as single, should be 3
#8 K08      B Clinic_1 2020-03-06 2020-03-21              5 ## should be 4
#9 K09      B Clinic_1 2020-03-18 2020-03-22              5 ## should be 4

【问题讨论】:

    标签: r date


    【解决方案1】:

    使用data.table的选项:

    setkey(setDT(have), clinic, strain, datein, dateout)
    have[, g := cumsum(c(0L, (shift(datein, -1L) > cummax(as.integer(dateout)))[-.N])), 
      .(clinic, strain)][, 
        g := rleid(clinic, strain, g)]
    

    还有:

    have[, g02 := cumsum(datein > shift(cummax(as.integer(dateout)), fill=dateout[1L])),
        .(clinic, strain)][,
            g2 := rleid(clinic, strain, g02)]
    

    输出:

        id strain   clinic     datein    dateout g g2
    1: K01      A Clinic_1 2020-01-01 2020-01-05 1  1
    2: K02      A Clinic_1 2020-01-03 2020-01-16 1  1
    3: K05      B Clinic_1 2020-02-18 2020-02-27 2  2
    4: K06      B Clinic_1 2020-02-20 2020-02-23 2  2
    5: K07      B Clinic_1 2020-02-21 2020-02-22 2  2
    6: K08      B Clinic_1 2020-03-06 2020-03-21 3  3
    7: K09      B Clinic_1 2020-03-18 2020-03-22 3  3
    8: K03      A Clinic_2 2020-02-03 2020-02-09 4  4
    9: K04      A Clinic_2 2020-02-09 2020-02-19 4  4
    

    cummax 的想法来自 David Aurenburg 帖子:How to flatten / merge overlapping time periods

    【讨论】:

    • 感谢您的深刻见解 - 在此解决方案中,K07 与 K08 和 K09 分组,但应与 K05/K06 分组。我根据您的方法尝试了几种替代方法,但无法使其正常工作。有任何想法吗?感谢您迄今为止的帮助!
    • 完美!谢谢
    【解决方案2】:

    我们可以使用rleid

    library(dplyr)
    library(data.table)
    have %>% 
      mutate(overlap_number = rleid(strain, clinic, 
           cumsum(datein > lag(dateout, default = first(dateout)))))
    #    id strain   clinic     datein    dateout overlap_number
    #1 K01      A Clinic_1 2020-01-01 2020-01-05              1
    #2 K02      A Clinic_1 2020-01-03 2020-01-16              1
    #3 K03      A Clinic_2 2020-02-03 2020-02-09              2
    #4 K04      A Clinic_2 2020-02-09 2020-02-19              2
    #5 K05      B Clinic_1 2020-02-18 2020-02-27              3
    #6 K06      B Clinic_1 2020-02-20 2020-02-23              3
    #7 K07      B Clinic_1 2020-02-21 2020-02-22              3
    #8 K08      B Clinic_1 2020-03-06 2020-03-21              4
    #9 K09      B Clinic_1 2020-03-18 2020-03-22              4
    

    【讨论】:

    • Beautiful - 不知道 rleid 函数并且在示例数据上完美运行。当我将其应用于我的实际数据时,会出现一个小问题——3+ 的组有时会有很长的间隔,其中包含其他几个不相交的日期。例如,我在另一个更改了K07 日期的数据集中进行了编辑。我尝试将...&gt;lag(dateout...) 更改为...&gt;min(dateout...),但没有奏效。还有其他想法吗?
    • @jpsmith 与您需要的重叠数相同
    • 我添加了我的输出和注释;当我在 want2 上运行它时,它会创建 5 个重叠数,因为它将 K07 视为一个单元
    猜你喜欢
    • 2019-09-14
    • 2017-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 2023-01-10
    • 1970-01-01
    相关资源
    最近更新 更多