【问题标题】:Find n overlapping dates within n number of days在 n 天内查找 n 个重叠日期
【发布时间】:2021-06-21 16:40:30
【问题描述】:

我希望找到 >=4 个在 90 天内发生在一个组内的唯一事件,然后标记 ID。

只是一个测试示例:

library(dplyr)

set.seed(1)

test <- data.frame(
  PATID = sample(1:1e4, 1e5, replace = TRUE),
  PROV = sample(1:50, 1e5, replace = TRUE),
  GROUP = sample(0:1, 1e5, replace = TRUE),
  DATE = as.Date(sample(
    as.Date("2020-01-01"):as.Date("2020-12-31"),
    1e5,
    replace = TRUE
  ), origin = "1970-01-01")
)

如果我们查看PATID==5,我们可以看到有 4 个独特的 PROVs,它们在 90 天内的重叠日期在我们的兴趣组内,因此应该被标记。

> test %>% filter(PATID==5) %>% arrange(GROUP,DATE)
   PATID PROV GROUP       DATE
1      5    2     0 2020-05-07
2      5    3     0 2020-05-20
3      5    3     0 2020-11-15
4      5   49     0 2020-12-14
5      5   45     1 2020-02-16
6      5   50     1 2020-03-19
7      5   38     1 2020-03-25
8      5   27     1 2020-03-29
9      5   42     1 2020-08-30
10     5   46     1 2020-11-03
11     5   25     1 2020-11-13
12     5   29     1 2020-12-26
> as.Date("2020-03-29")-as.Date("2020-02-16")<=90
[1] TRUE

最终,我正在寻找 90 天内 GROUP==1GROUP==0 与 >=4 唯一 PROVs 的比例。理想情况下,由于数据的规模,我更喜欢使用 data.table。

尝试一些代码:

test %>%
  filter(PATID %in% 1:5) %>%
  group_by(PATID,GROUP) %>%
  arrange(GROUP, DATE) %>%
  mutate(lag = DATE - lag(DATE),
         day_count = case_when(lag <= 90 ~ TRUE,
                               is.na(lag) ~ TRUE,
                               TRUE ~ FALSE)) %>%
  mutate(crit = cumsum_reset(day_count)) %>% 
  ungroup() %>%
  group_by(PATID) %>%
  mutate(flag = case_when(max(crit) >= 4 ~ 1,
                          TRUE ~ 0)) %>% 
  arrange(PATID)

越来越近了,只需要理清90的窗口而不是粗略地测试每个日期是否在90天内。

【问题讨论】:

  • 是的,根据 PATID。
  • 好吧,标志(如果这是最好的系统)将在 PATID 级别。不过,该比例将是符合和不符合标准的 PATID 的总和。
  • 90d 窗口重叠的情况呢?你还能重复使用第一个窗口中的 PROV 吗?

标签: r dplyr data.table


【解决方案1】:

也许以下就是您所追求的。请检查逻辑是否是您的意思。我留下了比必要的更明确的内容,以便更容易理解这个想法。主要思想是,如果在排序后有来自同一 PATDI 和 GROUP 的观察结果在第三个滞后 diff_3 := DATE - shift(DATE, 3) 的 90 天内,则应该标记它。这是通过检查diff_check = diff_3&lt;=90 来完成的。如果标记了任何 PATID/GROUP 的任何观察,则在仅按 PATID 分组后,相应的 ID 将由 keep = max(diff_check, na.rm = TRUE, pmin = 0) 标记。

  • 使用第三个滞后来解释 4 个或更多且严格不超过 4 个观察值。
  • 总的来说,这有意义吗?
library(data.table)
set.seed(1)
test <- data.frame(
  PATID = sample(1:1e4, 1e5, replace = TRUE),
  PROV = sample(1:50, 1e5, replace = TRUE),
  GROUP = sample(0:1, 1e5, replace = TRUE),
  DATE = as.Date(sample(
    as.Date("2020-01-01"):as.Date("2020-12-31"),
    1e5,
    replace = TRUE
  ), origin = "1970-01-01")
)
test %>% filter(PATID==5) %>% arrange(GROUP,DATE)
#> Error in test %>% filter(PATID == 5) %>% arrange(GROUP, DATE): could not find function "%>%"

dt <- as.data.table(test)
dt <- dt[order(PATID, GROUP, DATE)]
dt[, diff_3 := DATE - shift(DATE, 3), by = c("PATID", "GROUP")]

# check amount of unique values of PROV in previous 4 observations
dt[, unique_last_4 := frollapply(x = PROV, n = 4, FUN = uniqueN), by = c("PATID", "GROUP")]

# check if within 90 days and unique PROVs 
dt[, diff_check := diff_3<=90 & unique_last_4==4, by = c("PATID", "GROUP")]

# final check to flag all observations of ID that satisfied at least once the above checks
dt[, to_keep := max(diff_check, na.rm = TRUE, pmin = 0), by = "PATID"]
# NOTE: unsure if you mean to group only by PATID here or by PATID & GROUP.

head(dt[to_keep==1], 20)
#>     PATID PROV GROUP       DATE   diff_3 unique_last_4 diff_check to_keep
#>  1:     5    2     0 2020-05-07  NA days            NA         NA       1
#>  2:     5    3     0 2020-05-20  NA days            NA         NA       1
#>  3:     5    3     0 2020-11-15  NA days            NA         NA       1
#>  4:     5   49     0 2020-12-14 221 days             3      FALSE       1
#>  5:     5   45     1 2020-02-16  NA days            NA         NA       1
#>  6:     5   50     1 2020-03-19  NA days            NA         NA       1
#>  7:     5   38     1 2020-03-25  NA days            NA         NA       1
#>  8:     5   27     1 2020-03-29  42 days             4       TRUE       1
#>  9:     5   42     1 2020-08-30 164 days             4      FALSE       1
#> 10:     5   46     1 2020-11-03 223 days             4      FALSE       1
#> 11:     5   25     1 2020-11-13 229 days             4      FALSE       1
#> 12:     5   29     1 2020-12-26 118 days             4      FALSE       1
#> 13:     7    1     0 2020-04-10  NA days            NA         NA       1
#> 14:     7   44     0 2020-04-29  NA days            NA         NA       1
#> 15:     7   27     0 2020-05-05  NA days            NA         NA       1
#> 16:     7   41     0 2020-06-11  62 days             4       TRUE       1
#> 17:     7   35     0 2020-06-30  62 days             4       TRUE       1
#> 18:     7   11     0 2020-12-18 227 days             4      FALSE       1
#> 19:     7   24     1 2020-12-24  NA days            NA         NA       1
#> 20:     7   13     1 2020-12-29  NA days            NA         NA       1

reprex package (v2.0.0) 于 2021-06-22 创建

dplyr 版本

test_keep <- test %>% arrange(PATID, GROUP, DATE) %>%
  head(1000) %>% # otherwise it takes too long in my pc, which shows data.table's efficiency! 
  group_by(PATID, GROUP) %>%
  mutate(diff_3 = DATE - lag(DATE, 3),
         diff_check = diff_3<=90, 
         unique_last_4 = frollapply(x = PROV, n = 4, FUN = uniqueN)
  ) %>% group_by(PATID) %>%
  mutate(keep = max(diff_check, na.rm = TRUE, pmin = 0)) %>%
  arrange(PATID, GROUP)

test_keep %>% filter(keep==1) %>% head(20)

【讨论】:

  • 此处的示例数据并未真正显示出来,但 IRL PROV(提供者)与 PATID(患者)高度相关,因此绝对需要唯一的 PROV。
  • 现在检查 PROV 的唯一性。我希望它现在可以解决您的问题,但请检查极端情况:)
  • 谢谢,我想这对我有用。我认为一个很好的检查是将 PROV 样本降低到 1:5 之类的值。我没有发现任何漏掉的边缘案例。
【解决方案2】:

基于我正在寻找在 90 天内访问 >=4 家提供者的患者的年度“群体”比例,您可以试试这个:

library(data.table) #data.table 1.13.2
setDT(test)[, c("d90ago", "d90aft") := .(DATE - 90L, DATE + 90L)]
setkey(test, PATID, DATE)
test[, grp := 
    .SD[.SD, on=.(PATID, DATE>=d90ago, DATE<=d90aft), by=.EACHI, +(length(unique(x.PROV))>=4L)]$V1
]

以上规定允许在 90 天的重叠窗口内重复使用 PROV。

【讨论】:

  • 深入研究数据,我可以看到,如果每个 PATID 都满足条件,这不是二进制标签,即 PATID 属于 grp。我为我的糟糕描述道歉。我正在寻找访问 >=4 提供者的患者,该组是处方。因此,我正在寻找在 90 天内访问 >=4 个不同提供者的患者。
【解决方案3】:

这个问题有一些模棱两可的地方,所以这可能不太正确。我尝试使用dplyr 和本地数据帧来执行此操作,但自连接会导致溢出(100,000 乘以 100,000)。 它似乎使用data.table 和使用具有OVERLAPS 函数的PostgreSQL 工作。 (请注意,我使用小写的变量名来简化 SQL 的使用。)

在下面的答案中,我从一次患者就诊 ((patid, prov, group, date) 组合) 开始,并期待 90 天来记录该患者 (patid) 对其他 提供者 (@987654327) 的所有访问@)。然后,我计算了该前瞻期间不同提供者的数量(当没有访问时,这将是 NA,就像查看样本中患者的最后一次访问时一样)。然后,我计算在随后的 90 天内其他个不同提供者的数量为 3 或更多的访问次数。

最后,我按(group, year) 分组,并计算在随后的 90 天内访问至少三个其他提供商的访问比例。考虑到数据的生成方式,两组在这个指标上看起来相似也就不足为奇了。

请注意,每次患者就诊都会在此处形成一个观察单元。在实践中,在计算统计数据或进行某种其他类型的聚合之前,通过(例如)(patid, year) 聚合可能是有意义的。

library(data.table)
library(dplyr, warn.conflicts = FALSE)

set.seed(1)

test <- tibble(
    patid = sample(1:1e4, 1e5, replace = TRUE),
    prov = sample(1:50, 1e5, replace = TRUE),
    group = sample(0:1, 1e5, replace = TRUE),
    date = as.Date(sample(
        as.Date("2020-01-01"):as.Date("2020-12-31"),
        1e5,
        replace = TRUE
    ), origin = "1970-01-01")) %>%
    as.data.table()
test 
#>         patid prov group       date
#>      1:  1017    6     1 2020-08-03
#>      2:  8004   34     0 2020-12-15
#>      3:  4775   32     0 2020-06-21
#>      4:  9725   47     1 2020-09-25
#>      5:  8462   15     0 2020-03-05
#>     ---                            
#>  99996:   949   47     0 2020-07-05
#>  99997:  2723   37     0 2020-08-18
#>  99998:   201   27     1 2020-01-06
#>  99999:   163    9     0 2020-03-06
#> 100000:  3204   48     1 2020-11-17

df_overlap <- 
    test %>% 
    inner_join(test, by = "patid", suffix = c("", "_other")) %>%
    filter(prov != prov_other) %>%
    filter(date_other >= date & date_other <= date + 90L)

mt_4_provs_df <-
    df_overlap %>% 
    group_by(patid, prov, group, date) %>%
    summarize(n_providers = n_distinct(prov_other), .groups = "drop")

results <- 
    test %>%
    left_join(mt_4_provs_df, by = c("patid", "prov", "group", "date")) %>%
    mutate(mt_4_provs = n_providers >= 3,
           year = year(date)) %>%
    group_by(group, year) %>%
    summarize(prop_mt_4_provs = mean(mt_4_provs, na.rm = TRUE),
              .groups = "drop")
    
results
#> # A tibble: 2 x 3
#>   group  year prop_mt_4_provs
#>   <int> <int>           <dbl>
#> 1     0  2020           0.426
#> 2     1  2020           0.423

reprex package (v2.0.0) 于 2021-06-22 创建

【讨论】:

  • 我正在寻找总体组内的比例,而不是每个 PATID 中按组划分的 PROV 的比例。
  • 我明白了。我可能在这里做出了错误的假设,因为我对变量的含义并不完全清楚。我想一个问题是data.table 版本中的df_overlap 是否正在做你想做的事情。如果是这样,调整后面的步骤以达到您想要的效果可能并不难。 (这里的主要问题似乎是使用 data.table 而不是“常规”数据框对于基于连接的解决方案有很大的不同。)
  • 用更简单的英语:我正在寻找在 90 天内访问 >=4 个提供者的患者的年度“组”比例。所以我真的希望这一切都归结为每年的一个百分比数字,同时能够在需要时回顾每一步。
  • 计数的方法似乎有很多。假设有一位患者每 20 天访问一次新的提供者。标记提供者AB、……,如果该患者按字母顺序排列,则将有许多 90 天期间至少有 4 个提供者:(A, B, C, D)(B, C, D, E)、……。其中一些将重叠。在上面修改后的答案中,我有效地计算了这些时期中的每一个(一个以A 开头,一个以B 开头,等等)。一个小问题是,我怀疑在您的真实数据中,患者属于一组或另一组。但在模拟数据中,患者在组间“移动”。
猜你喜欢
  • 1970-01-01
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-24
相关资源
最近更新 更多