我有这个数据框的例子。抱歉,我无法分享我的数据集,但它基本上类似于 df。
df <- data.frame(member_id = c(603, 603, 603),
fill_dt = c("02/17/2005", "06/13/2005", "08/11/2005"),
drug = c("a", "a", "a"),
days_supply = c(30,30,30)) # could vary depending on the prescription
我试图找出研究期间(0,180 天)提供药物的天数比例。
这个输出不是问题,我可以使用排列、row_number()、pivot_wider 的组合来实现它。基本上做的就是报纸上做的事情,只不过是在 R 中。他们的开始日是第一次购买处方。由于研究在首次购买后 180 天结束,因此 end_dt = fill_dt1+179。如果有人好奇的话,这是他们之前输出的 SAS 代码:
proc sort data=claims;
by member_id fill_dt;
run;
proc transpose data = claims out=fill_dates (drop=_name_) prefix = fill_dt;
by member_id;
var fill_dt;
run;
proc transpose data = claims out=days_supply (drop=_name_) prefix = days_supply;
by member_id;
var days_supply;
run;
data both;
merge fill_dates days_supply;
by member_id;
format start_dt end_dt mmddyy10.;
start_dt=fill_dt1;
end_dt=fill_dt1+179;
run;
这就是事情变得复杂的地方。我想计算 180 天/研究期内单一药物的供应天数。该论文提供了以下 SAS 解决方案:
data pdc;
set both;
array daydummy(180) day1-day180;
array filldates(*) fill_dt1 - fill_dt11;
array days_supply(*) days_supply1-days_supply11;
do ii=1 to 180; daydummy(ii)=0;end;
do ii=1 to 180;
do i = 1 to dim(filldates) while (filldates(i) ne .);
if filldates(i)<= start_dt + ii -1 <= filldates(i)+days_supply(i)-1
then daydummy(ii)=1;
end;
end;
drop i ii;
dayscovered=sum(of day1 - day180);label dayscovered='Total Days Covered';
p_dayscovered=dayscovered/180;label p_dayscovered='Proportion of Days Covered';
run;
基本上,论文会找到该人在哪几天(超过 180 天的时间段)服用药物。提供处方的天数(取决于 days_supply 变量),该天为 1,否则为 0。然后,他们将涵盖的天数 (dayscovered) 相加,并将该变量除以整个研究期间以获得该变量p_dayscovered。预期结果如下:
本文未显示所有列。他们的结果包括全部 180 天。因此,列 day6-day29 实际上不是一列,而是 day6、day7、...、day29,这些列填充了数字 1。 事情实际上变得更加复杂,因为有些处方是重叠的。例如,患者 603 在上一张处方结束前几天购买了新处方。该论文处理重叠的方法是改变新的处方间隔,因为从逻辑上讲,一个人会完成旧的处方以开始新的处方。因此,如果旧处方在 08/05/2005 结束,并且旧处方是在 07/30/2005 购买的,则新处方期限会被推迟,因此实际上会在 08/06/2005 开始。患者可能有多个重叠,因此需要注意这些重叠。事情总是会发生变化,除非处方不重叠。该论文表示,可以在之前的代码中(第二个 DO 之后)使用以下 SAS 代码来实现所需的输出:
do u=2 to 11 while (filldates(u) ne .);
if filldates(u)<filldates(u-1)+days_supply(u-1)
then filldates(u)=filldates(u-1)+days_supply(u-1);
end;
我想这使得 SAS 代码看起来像这样(如果我不明白,请随时纠正我):
data pdc;
set both;
array daydummy(180) day1-day180;
array filldates(*) fill_dt1 - fill_dt11;
array days_supply(*) days_supply1-days_supply11;
do ii=1 to 180; daydummy(ii)=0;end;
do ii=1 to 180;
do i = 1 to dim(filldates) while (filldates(i) ne .);
if filldates(i)<= start_dt + ii -1 <= filldates(i)+days_supply(i)-1
then daydummy(ii)=1; end;
do u=2 to 11 while (filldates(u) ne .);
if filldates(u)<filldates(u-1)+days_supply(u-1)
then filldates(u)=filldates(u-1)+days_supply(u-1);
end;
end;
drop i ii;
dayscovered=sum(of day1 - day180);label dayscovered='Total Days Covered';
p_dayscovered=dayscovered/180;label p_dayscovered='Proportion of Days Covered';
run;
我想知道是否可以使用 R(第二、第三和第四个 SAS 代码块)来完成所有这些操作。第一部分已得到处理。但我在计算天数列和重叠方面惨遭失败。有问题的论文是:https://support.sas.com/resources/papers/proceedings/proceedings/forum2007/043-2007.pdf
编辑:我有兴趣将这一时期的每一天保留为一列,就像提供的照片和文章中一样(填写处方的日期为 1,否则为 0)。这样我就可以计算出一个人每周接触药物的天数。这就是为什么转移重叠的日子也很重要,因为我能够跟踪这些日子。
好吧,我想当你第一次提出这个问题时我知道你想做什么。
首先,最好的(我认为)库是
tidyverse
和 lubridate
。我首先添加更多行是为了提供更多视图。
structure(list(member_id = c(603, 603, 603, 604, 604), fill_dt = c("02/17/2005",
"06/13/2005", "08/11/2005", "06/15/2005", "08/13/2005"), drug = c("a",
"a", "a", "a", "a"), days_supply = c(30, 30, 30, 60, 30)), class = "data.frame", row.names = c(NA,
-5L))
df1 <- df %>%
mutate(fill_dt = as.Date(fill_dt, format = "%m/%d/%y")) %>%
group_by(member_id, drug) %>%
filter(row_number() == 1) %>%
mutate(study_end = fill_dt + days(180)) %>%
transmute( days_range = map2(fill_dt, study_end, seq, by = "1 day")) %>%
unnest(days_range)
您的数据应如下所示:
# A tibble: 362 x 3
# Groups: member_id, drug [2]
member_id drug days_range
<dbl> <chr> <date>
1 603 a 2020-02-17
2 603 a 2020-02-18
3 603 a 2020-02-19
4 603 a 2020-02-20
5 603 a 2020-02-21
6 603 a 2020-02-22
7 603 a 2020-02-23
8 603 a 2020-02-24
9 603 a 2020-02-25
10 603 a 2020-02-26
# i 352 more rows
第一部分从长远角度获取您的数据。如前所述,SAS 和 R 之间的区别是 SAS 是基于行的,而 R 是基于列的。这就是为什么以这种方式构建数据很重要。
然后我们需要通过
summarise
和 member_id
创建标志和 drug
数据。
df_fin <- df1 %>%
left_join(df %>%
mutate(fill_dt = as.Date(fill_dt, format = "%m/%d/%y"),
fill_dt_end = fill_dt + days(days_supply)) %>%
group_by(member_id, drug), by = c("member_id", "drug") ,
relationship = "many-to-many") %>%
mutate(covered_flg = if_else(days_range %within% interval(fill_dt, fill_dt_end), 1, 0)) %>%
group_by(member_id, drug, days_range) %>%
summarise(covered_flg = max(covered_flg)) %>%
ungroup(days_range) %>%
summarise(covered_days = sum(covered_flg)) %>%
ungroup() %>% mutate(prop_days_covered = covered_days/180)
上面的代码首先通过
df1
和 left_joins
建立多对多关系中的 member_id
和 drug
的开始日期 (fill_dt
) 和结束日期 (fill_dt_end
= fill_dt + days supply
)处方配齐。根据日期范围,如果长格式的日期(来自 df1
)在 fill_dt
和 fill_dt_end
之间的范围内,此代码将创建一个标志。然后由于多对多连接,我们得到 max
。
这应该产生
df_fin
# A tibble: 2 x 4
member_id drug covered_days prop_days_covered
<dbl> <chr> <dbl> <dbl>
1 603 a 67 0.372
2 604 a 90 0.5