2016-01-13 9 views
7

Come posso trovare l'ultimo valore , prima test.day, per ogni (loc.x, loc.y) coppia?rotolamento Data.Table uniscono da gruppo

dt <- data.table( 
    loc.x = as.integer(c(1, 1, 3, 1, 3, 1)), 
    loc.y = as.integer(c(1, 2, 1, 2, 1, 2)), 
    time = as.IDate(c("2015-03-11", "2015-05-10", "2015-09-27", 
        "2015-11-25", "2014-09-13", "2015-08-19")), 
    value = letters[1:6] 
) 

setkey(dt, loc.x, loc.y, time) 
test.day <- as.IDate("2015-10-01") 

uscita richiesto:

loc.x loc.y value 
1:  1  1  a 
2:  1  2  f 
3:  3  1  c 

risposta

6

Un'altra opzione è quella di utilizzare la funzione last:

dt[, last(value[time < test.day]), by = .(loc.x, loc.y)] 

che dà:

loc.x loc.y V1 
1:  1  1 a 
2:  1  2 f 
3:  3  1 c 
+6

Penso che 'dt [time

+0

Grazie David, buon punto – Amitai

6

È possibile primo sottoinsieme le righe in cui time < test.day (che dovrebbe essere abbastanza efficiente, perché non è fatto da gruppo) e poi selezionare l'ultima value per gruppo. Per farlo è possibile utilizzare tail(value, 1L) o, come suggerito da Floo0, value[.N], con conseguente:

dt[time < test.day, tail(value, 1L), by = .(loc.x, loc.y)] 
# loc.x loc.y V1 
#1:  1  1 a 
#2:  1  2 f 
#3:  3  1 c 

o

dt[time < test.day, value[.N], by = .(loc.x, loc.y)] 

Si noti che questo funziona perché i dati vengono ordinati a causa di setkey(dt, loc.x, loc.y, time).

+3

di voi potrebbe usare 'valore [.N]' ', invece, se la coda (valore, 1L) '. – Rentrop

+0

@ Floo0, certo, questa è un'altra opzione. –

5

Ecco un'altra opzione utilizzando un rotolamento unirsi dopo la creazione di una tabella di ricerca

indx <- data.table(unique(dt[ ,.(loc.x, loc.y)]), time = test.day) 
dt[indx, roll = TRUE, on = names(indx)] 
# loc.x loc.y  time value 
# 1:  1  1 2015-10-01  a 
# 2:  1  2 2015-10-01  f 
# 3:  3  1 2015-10-01  c 

o un'opzione molto simile suggerita da @eddi

dt[dt[, .(time = test.day), by = .(loc.x, loc.y)], roll = T, on = c('loc.x', 'loc.y', 'time')] 

O un uno di linea, che sarà meno efficiente poiché chiamerà lo [.data.table dal gruppo

dt[, 
    .SD[data.table(test.day), value, roll = TRUE, on = c(time = "test.day")], 
    by = .(loc.x, loc.y) 
    ] 
# loc.x loc.y V1 
# 1:  1  1 a 
# 2:  1  2 f 
# 3:  3  1 c 
+1

Hmm, che dire di 'dt [dt [,. (Time = test.day), di =. (Loc.x, loc.y)], roll = T, on = c ('loc.x', 'loc .y ',' time ')] 'invece, per evitare il' [.data.table' in un ciclo? – eddi

+0

Sì, il mio pensiero era 'indx <- data.table (unique (dt [,. (Loc.x, loc.y)]), time = test.day); dt [indx, roll = TRUE, on = names (indx)] 'in realtà, ma tutto questo sembra un over kill e stavo per cancellarlo. –

+0

@eddi ho aggiunto entrambi nella risposta. Immagino che ora sarà più competitivo. –