Вот еще вариант:
cols <- paste0("val", 1L:2L)
trt[, paste0("prev", cols) := lapply(.SD, nafill, type="locf"), group, .SDcols=cols]
trt[, outval1 := fifelse(is.na(val1), prevval1 * cumprod(ref), val1), .(group, rleid(is.na(val1)))]
trt[, outval2 := fifelse(is.na(val2), prevval2 * cumprod(ref), val2), .(group, rleid(is.na(val2)))]
редактировать для нескольких val
столбцов. Может быть, что-то вроде этого:
cols <- paste0("V", 1L:30L)
for (x in cols) {
trt[, c("prev", "ri") := {
v <- get(x)
.(nafill(v, "locf"), rleid(is.na(v)))
}, group]
trt[, paste0("out", x) := {
v <- get(x)
fifelse(is.na(v), prev * cumprod(ref), v)
}, .(group, ri)]
}
или используя melt
, что будет быстрее:
mDT <- melt(trt[, rn := .I], measure.vars=patterns("^V"))
mDT[, pv := nafill(value, "locf"), group]
mDT[, nv := fifelse(is.na(value), pv * cumprod(ref), value),
.(group, variable, rleid(is.na(value)))]
dcast(mDT, rn + group + reflev + ref ~ variable, value.var="nv")
образцы данных:
library(data.table)
set.seed(0L)
nc <- 30L
nr <- 3e3L
trt <- data.table(group = rep(1:(nr/5L), each=5L),
reflev = 1+runif(nr)/10,
as.data.table(matrix(sample(c(NA,10,20,30), nc*nr, TRUE), ncol=nc)))
trt[ , ref:= round(reflev/shift(reflev), 2), by = group]