В качестве альтернативы, это может быть решено с помощью комбинированного перекрестного соединения и неэквивалентного объединения и последующего изменения формы из длинного в широкий формат.
library(data.table)
months <- seq(as.Date("2019-01-01"), Sys.Date(), by = "month")
cbind(
dates,
setDT(dates)[, lapply(.SD, as.Date, format = "%m/%d/%y")][
is.na(Discharge), Discharge := Sys.Date()][
, rn := .I][
.(months), on = .(Admission <= V1, Discharge >= V1)
, allow.cartesian = TRUE, .(rn, V1, active = "Active")][
, V1 := factor(V1, labels = format(months, "%b-%y"))][
, dcast(.SD, rn ~ V1, value.var = "active", fill = "Inactive")][
, rn := NULL]
)
Admission Discharge Jan-19 Feb-19 Mrz-19 Apr-19 Mai-19 Jun-19
1: 12/3/18 4/3/19 Active Active Active Active Inactive Inactive
2: 01/7/19 <NA> Inactive Active Active Active Active Active
3: 02/25/19 03/02/19 Inactive Inactive Active Inactive Inactive Inactive
Пояснение
months
содержит вектор контрольных дат.Здесь используется первый день каждого месяца. - Даты
Admission
и Discharge
приводятся от символа к классу Date
, чтобы можно было рассчитать дату. - Любые пропущенные
Discharge
даты заполняются до текущей даты. - Добавляется номер строки, чтобы сохранить исходный порядок строк в последующем преобразовании.
- Затем он соединяется справа с
months
.Это неэквивалентное перекрестное объединение , которое возвращает только случаи, когда первый день месяца V1
находится между датами приема и выписки.V1
- это имя столбца по умолчанию, создаваемое при превращении вектора months
в список на .(months)
.allow.cartesian = TRUE
указывает на перекрестное соединение.При объединении создается новый столбец active
со значением по умолчанию "Active"
. V1
преобразуется в коэффициент с соответствующим названием месяцев, например, "Jan-19"
, "Feb-19"
,и т. д. Это гарантирует, что даты будут отображаться в правильном порядке (вместо сортировки лексикографически) при последующем преобразовании. dcast()
изменяет данные с длинного на широкий формат, в то время как отсутствующие записи заполняются "Inactive"
. - Номера строк удалены.
- Наконец, результат объединяется с исходным набором данных
dates
с использованием cbind()
.
Укороченная версия
Выше код пытается воспроизвести ожидаемый результат OP как можно ближе.Та же самая информация (но в другом виде) может быть получена с использованием более краткого кода:
setDT(dates)[, lapply(.SD, as.Date, format = "%m/%d/%y")][
is.na(Discharge), Discharge := Sys.Date()][
, rn := .I][
.(months), on = .(Admission <= V1, Discharge >= V1), allow.cartesian = TRUE
, .(rn, Admission = x.Admission, Disscharge = x.Discharge, V1)][
, dcast(.SD, rn + ... ~ V1, length)]
, который возвращает
rn Admission Disscharge 2019-01-01 2019-02-01 2019-03-01 2019-04-01 2019-05-01 2019-06-01
1: 1 2018-12-03 2019-04-03 1 1 1 1 0 0
2: 2 2019-01-07 2019-06-07 0 1 1 1 1 1
3: 3 2019-02-25 2019-03-02 0 0 1 0 0 0
Данные
library(data.table)
dates <- fread("Admission Discharge Jan-19 Feb-19 Mar-19
12/3/18 4/3/19 Active Active Active
01/7/19 NA Inactive Active Active
02/25/19 03/02/19 Inactive Inactive Active"
, select = 1:2)
dates
Admission Discharge
1: 12/3/18 4/3/19
2: 01/7/19 <NA>
3: 02/25/19 03/02/19