Если я правильно понимаю, ОП хочет
- расширить каждую строку в последовательность дней между указанными
Start
и End
датами, - накапливать
Dose
для каждого Subject
во все дни.
Изменение формы " от ширины к длине ", например, gather()
или melt()
, здесь не требуется (и указывает нанеправильное направление, ИМХО).
dplyr
и tidyr
Вот реализация, использующая dplyr
и tidyr
.Поскольку seq()
не принимает векторные аргументы, нам нужно сгруппировать по каждой строке и unnest()
расширенные дни.
library(dplyr)
library(tidyr)
dat %>%
group_by(rn = row_number()) %>%
mutate(Day = list(seq(Start, End, "1 day"))) %>%
unnest() %>%
arrange(Subject, Day) %>%
group_by(Subject)%>%
mutate(Sum_Dose = cumsum(Dose)) %>%
select(Subject, Period, Sum_Dose, Day)
Обратите внимание, что упорядочение по Day
перед вызовом cumsum()
- это простопредварительная осторожность в случае, если dat
еще не заказан или в случае перекрывающихся диапазонов дат.
# A tibble: 392 x 5
# Groups: Subject [3]
Subject Period Dose DAY Sum_Dose
<fct> <fct> <dbl> <date> <dbl>
1 13434 MAD 400 2017-04-18 400
2 13434 MAD 400 2017-04-19 800
3 13434 MAD 400 2017-04-20 1200
4 13434 MAD 400 2017-04-21 1600
5 13434 MAD 400 2017-04-22 2000
6 13434 MAD 400 2017-04-23 2400
7 13434 MAD 400 2017-04-24 2800
8 13434 MAD 400 2017-04-25 3200
9 13434 MAD 400 2017-04-26 3600
10 13434 MAD 400 2017-04-27 4000
# ... with 382 more rows
data.table
Версия data.table
реализуеттот же подход, но менее многословный, так как «непринятие» делается косвенно.
library(data.table)
setDT(dat)[, rn := .I][
, .(Subject, Period, Dose, Day = seq(Start, End, "1 day")), by = rn][
order(Day), .(Period, Sum_Dose = cumsum(Dose), Day), keyby = Subject]
Subject Period Sum_Dose Day
1: 13434 MAD 400 2017-04-18
2: 13434 MAD 800 2017-04-19
3: 13434 MAD 1200 2017-04-20
4: 13434 MAD 1600 2017-04-21
5: 13434 MAD 2000 2017-04-22
---
388: 14544 OSE 128800 2019-02-05
389: 14544 OSE 129600 2019-02-06
390: 14544 OSE 130400 2019-02-07
391: 14544 OSE 131200 2019-02-08
392: 14544 OSE 132000 2019-02-09