我有一个数据集,其中包含个人 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)
)
谢谢!虽然我使用数字作为开始和结束,但我将调整此代码以使用日期。我正在尝试生成一个包含所有连续保险范围的独特时期的数据框。
我无法想出一个循环、变异或条件函数来完成这个任务。
我认为这个解决方案应该适用于每种情况,因为序列不是太长,因为我构建了单独的序列然后验证(使用 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
您可以使用 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()
删除任何重复行。
我使用 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]