logica Ancora più semplice da @eddi (sotto i commenti) riducendo la rotonda quello mostrato qui sotto:
dt[, incr := diff(c(0, value)), by = group][, ans := cumsum(incr)]
Non sono sicuro di come si estende a più gruppi, ma ecco un esempio su dati con 3 gruppi:
# I hope I got the desired output correctly
require(data.table)
dt = data.table(group = c('a','b','c','a','a','b','c','a'),
value = c(10, 5, 20, 25, 15, 15, 30, 10),
desired = c(10, 15, 35, 50, 40, 50, 60, 55))
Aggiungi un rleid
:
dt[, id := rleid(group)]
Estrarre l'ultima riga per ogni group, id
:
last = dt[, .(value=value[.N]), by=.(group, id)]
last
avrà unico id
. Ora l'idea è di ottenere l'incremento per ogni id
, quindi unire + aggiornare di nuovo.
last = last[, incr := value - shift(value, type="lag", fill=0L), by=group
][, incr := cumsum(incr)-value][]
Registrati + Update:
dt[last, ans := value + i.incr, on="id"][, id := NULL][]
# group value desired ans
# 1: a 10 10 10
# 2: b 5 15 15
# 3: c 20 35 35
# 4: a 25 50 50
# 5: a 15 40 40
# 6: b 15 50 50
# 7: c 30 60 60
# 8: a 10 55 55
Non ne sono ancora sicuro dove/se questo si rompe .. guarderà con attenzione ora. L'ho scritto immediatamente in modo che ci siano più occhi su di esso.
Confrontando su 500 gruppi con 10.000 righe con la soluzione di David:
require(data.table)
set.seed(45L)
groups = apply(matrix(sample(letters, 500L*10L, TRUE), ncol=10L), 1L, paste, collapse="")
uniqueN(groups) # 500L
N = 1e4L
dt = data.table(group=sample(groups, N, TRUE), value = sample(100L, N, TRUE))
arun <- function(dt) {
dt[, id := rleid(group)]
last = dt[, .(value=value[.N]), by=.(group, id)]
last = last[, incr := value - shift(value, type="lag", fill=0L), by=group
][, incr := cumsum(incr)-value][]
dt[last, ans := value + i.incr, on="id"][, id := NULL][]
dt$ans
}
david <- function(dt) {
dt[, indx := .I]
res <- dcast(dt, indx ~ group)
for (j in names(res)[-1L])
set(res, j = j, value = res[!is.na(res[[j]])][res, on = "indx", roll = TRUE][[j]])
rowSums(as.matrix(res)[, -1], na.rm = TRUE)
}
system.time(ans1 <- arun(dt)) ## 0.024s
system.time(ans2 <- david(dt)) ## 38.97s
identical(ans1, as.integer(ans2))
# [1] TRUE
Questo è grande, grazie io sono! un po 'confuso riguardo il join e il rleid - non solo 'dt [, incr: = diff (c (0, valore)), per = gruppo] [, ans: = cumsum (incr)]' lavoro? (I' Non sono sicuro se mi manca qualche pezzo della logica) – eddi
Oh sì, penso che avrebbe funzionato! Quella strada rotonda si riduce al tuo one-liner – Arun
Wow che è un nice one-liner ... – andrew