Я подхожу к неизвестному количеству нескольких периодов даты в пределах основной последовательности периодов. Есть ли более читаемый или более компактный способ сделать это, чем мой путь? Я использую sqldf и data.table здесь, так как я использую обе библиотеки в проекте, но могу сделать это в чистой data.table, если это необходимо. Или наоборот. Другие хорошо развитые библиотеки также в порядке.R - транспонировать и вычислять различия между неизвестными столбцами даты. Более читаемый способ?
Нет hardcoding, я запускаю это с несколькими вариантами и не знаю максимального количества периодов в периоды. Количество в течение периодов не имеет теоретического верхнего (а может быть, 365) предел, но основная проверка здравомыслия должна составлять максимум около 6-15 периодов, в зависимости от спецификации.
Это представление рабочего кода, который я использую atm (записанный как функция в исходном скрипте).
Хотелось бы верить, что должна быть более короткая/читаемая функция. Есть ли что-нибудь, что мы можем сделать в dcast-части, которая вычисляет различия и применяет функцию sum? Я пробовал, но fun.aggregate кажется ограниченным более простыми операциями.
library("data.table")
library("sqldf")
Data <- data.table(
Fnr = c(22516, 22516, 22516, 45459, 45459),
Vernr = c(1,1,1,1,2),
Startdat = c("2010-01-01", "2010-01-01", "2012-01-01",
"2013-04-01", "2013-04-01"),
Endat = c("2010-12-31", "2010-12-31", "2012-05-19",
"2014-03-31", "2014-03-31"),
Fromdat = c("2010-02-21", "2010-08-16", NA, "2013-08-31", "2014-01-02"),
Tomdat = c("2010-05-16", "2010-09-11", NA, "2013-10-27", "2014-02-13")
)
tmp.eval <- "list(Fnr, Vernr, Startdat, Endat)"
dt_tmp <- Data[, nobs_id := order(Fromdat),
by = eval(parse(text = tmp.eval))]
dt_tmp <- dt_tmp[, c("Fromdat", "Tomdat") := list(as.Date(Fromdat),
as.Date(Tomdat))]
dt_tmp <- dcast(dt_tmp, Fnr + Vernr + ... ~ nobs_id,
value.var = c("Fromdat", "Tomdat"))
dt.colnames <- data.table(colnames(dt_tmp))
dt.col1 <- dt.colnames[substr(V1,1,3) == "Fro"][, c("nobs_id", "Fromdat") :=
list(order(V1),V1)]
dt.col2 <- dt.colnames[substr(V1,1,3) == "Tom"][, c("nobs_id", "Tomdat") :=
list(order(V1),V1)]
dt.set <- merge(dt.col1[,V1 := NULL], dt.col2[,V1 := NULL],
by = "nobs_id")
dt.set <- dt.set[, diff_col := paste(Tomdat,Fromdat, sep = "-")]
dt.set <- dt.set[, diff_col := paste(diff_col, " diff_",nobs_id, sep = "")]
dt.set <- dt.set[, diffvar_col := paste("as.numeric(diff_",nobs_id,")",
sep = "")]
str.diff <- paste(dt.set$diff_col, collapse = ",")
str.diffvar <- paste(dt.set$diffvar_col, collapse = ",")
str.diffvar <- paste("sum(", str.diffvar, ", na.rm = TRUE)")
dt_tmp <- sqldf(sprintf("SELECT *, %s FROM dt_tmp",
str.diff)
)
dt_tmp <- setDT(dt_tmp)[Startdat <= Endat,
corr_days := eval(parse (text = str.diffvar)),
by = list(Fnr, Vernr, Startdat, Endat)]
Для такого длинного вопроса может быть трудно получить прямой ответ здесь. Больше подходит для проверки кода. 1. Я бы не «dcast», а обрабатывал по группам как данные, которые уже хорошо смоделированы (* tidy *, используя недавно популяризированный термин). Тогда вам не нужно заменять имена столбцов переменными/строками, так как вы сохраняете данные в более общей структуре. 2. Не знаете, почему вы используете 'sqldf' здесь только для простого одиночного преобразования. 3. Я бы избегал 'eval (parse (' on text в пользу 'eval (' на языковых объектах, это хорошая функция R. – jangorecki
@jangorecki thx для подсказки, я обязательно буду думать об этом в будущем Sqldf - это артефакт, я сначала собирался в sqldf (я думал) и не менял его позже, так как планировал перезаписать функцию в любом случае. О части eval, thx, я все еще довольно новичок в использовании из R! – ErrantBard