如何创建和计算数字之间连续序列的周期

问题描述 投票:0回答:3

我有一个数据集,其中包含个人 ID 列 (enrolid)、开始编号 (start)、结束编号 (end)。我想创建一个包含所有连续周期的人周期级别的数据集,其中连续周期定义为行的起始编号小于或等于前一行的结束编号 + 1 的实例。例如,对于 enrolid 1,第一个连续的周期是从 0 到 15,因为这个人的第二行从 11 开始,这是最后一行结束数字的第一个数字。

这是我的数据:

have <- tibble(
  enrolid = c(1,1,1,1,2,2,2,2),
  start = c(0,11,19,24,2,14,17,37),
  end  = c(10,15,25,29,13,16,35,49)
)

这是我要的数据:

want <- tibble(
  enrolid = c(1,1,2,2),
  continuous_cov_start = c(0,19,2,37),
  continuous_cov_end = c(15,29,35,49),
  continuous_cov_sequence = c(1,2,1,2)
)

谢谢!虽然我使用数字作为开始和结束,但我将调整此代码以使用日期。我正在尝试生成一个包含所有连续保险范围的独特时期的数据框。

我无法想出一个循环、变异或条件函数来完成这个任务。

r loops conditional-statements counter period
3个回答
2
投票

我认为这个解决方案应该适用于每种情况,因为序列不是太长,因为我构建了单独的序列然后验证(使用 diff)连接序列之间是否存在差异 > 1 的块。

have <- data.frame(
  enrolid = c(1,1,1,1,2,2,2,2),
  start = c(0,11,19,24,2,14,17,37),
  end  = c(10,15,25,29,13,16,35,49)
)

have |>
  split(have$enrolid) |> 
  lapply(\(x) unique(do.call(c,
    Map(x$start, x$end, f = \(start, end) seq(start, end)))))  |>
  {\(x) Map(x, names(x), f = \(x, id) data.frame(
    enrolid = id,
    continuous_cov_start = x[which(diff(c(0,x))!=1)],
    continuous_cov_end = x[which(diff(c(x,0))!=1)],
    continuous_cov_sequence = seq_along(which(diff(c(0,x))!=1)))) }() |>
  do.call(what = rbind)
#>     enrolid continuous_cov_start continuous_cov_end continuous_cov_sequence
#> 1.1       1                    0                 15                       1
#> 1.2       1                   19                 29                       2
#> 2.1       2                    2                 35                       1
#> 2.2       2                   37                 49                       2

2
投票

您可以使用 lead() 函数将当前行的末尾与下一行的开始进行比较,然后使用 cumsum() 创建一个序列分组连续周期来实现这一点。这是生成想要的数据框的代码:

library(dplyr)

want <- have %>%
  arrange(enrolid, start) %>%
  group_by(enrolid) %>%
  mutate(
    continuous_cov_start = ifelse(start <= lead(end, default = last(end) + 1) + 1, start, NA),
    continuous_cov_end = ifelse(start <= lead(end, default = last(end) + 1) + 1, lead(end), NA),
    continuous_cov_sequence = cumsum(!is.na(continuous_cov_start))
  ) %>%
  filter(!is.na(continuous_cov_start)) %>%
  select(enrolid, continuous_cov_start, continuous_cov_end, continuous_cov_sequence) %>%
  distinct()

此代码首先通过 enrolid 和 start 排列数据框。然后,它按 enrolid 分组并使用

mutate()
创建三个新列:continuous_cov_start、continuous_cov_end 和 continuous_cov_sequence。

continuous_cov_start 列是使用

ifelse()
创建的,用于检查当前行的开始是否小于或等于下一行的结束 + 1。如果是,则将 continuous_cov_start 设置为当前行的开始.否则,它被设置为 NA。

continuous_cov_end 列的创建方式类似,但它使用

lead()
来获取下一行的末尾。

continuous_cov_sequence 列是使用

cumsum()
!is.na()
创建的序列分组连续周期。

最后,代码过滤掉 continuous_cov_start 为 NA 的行,选择感兴趣的列,并使用

distinct()
删除任何重复行。


0
投票

我使用 NuclearLemon 的帖子提供的技术写了这个答案,这些小的变化让我得到了我正在寻找的“想要”的数据框。

want <- have %>%
arrange(enrolid, start) %>%
group_by(enrolid) %>%
  mutate(
    continuous_cov_start = if_else(
      ((start > (lag(end)+1))|row_number()==1), start, NA),
    continuous_cov_sequence = cumsum(!is.na(continuous_cov_start))) %>% 
  group_by(enrolid, continuous_cov_sequence) %>% 
  mutate(continuous_cov_start= if_else(!is.na(continuous_cov_start), continuous_cov_start, first(continuous_cov_start))) %>% 
  filter(row_number()==n()) %>% 
  rename(continuous_cov_end=end) %>% 
  select(-start)

col_order <- c("enrolid", "continuous_cov_sequence", "continuous_cov_start",
               "continuous_cov_end")
want <- want[, col_order]
© www.soinside.com 2019 - 2024. All rights reserved.