2015-08-12 6 views
5

Il problema principale è descritto nel titolo della domanda. Andando direttamente all'esempio qui sotto.Aggiungi colonna per riferimento su rolling join

ho due set di dati:

library(data.table) 
dt1 <- data.table(date = as.Date("2015-06-28")+c(0L,3L,5L,7L), 
        key="date") 
dt2 <- data.table(date = as.Date("2015-06-30")+c(0:1,4L), 
        val = letters[7:9], 
        dummy = rep(NA,3), 
        key="date") 

voglio avere val colonna dalla dt2 aggiunti dt1 utilizzando rotolamento aderire.
La seguente dichiarazione produrrà un output simile a quello atteso:

dt2[dt1, roll=TRUE] 
#   date val dummy 
# 1: 2015-06-28 NA NA 
# 2: 2015-07-01 h NA 
# 3: 2015-07-03 h NA 
# 4: 2015-07-05 i NA 

Ci sono due problemi con questa affermazione:
1. non volevo avere dummy colonna
2. io voglio fare questo per riferimento:

address(dt1) 
# [1] "0x3b57540" 
address(dt2[dt1, roll=TRUE]) 
# [1] "0x3b4e1f0" 

Quindi, sto cercando di laminazione join e aggiungere colonna di riferimento per il mio dt1 e dt2, risultati attesi:

#   date val 
# 1: 2015-06-28 NA 
# 2: 2015-07-01 h 
# 3: 2015-07-03 h 
# 4: 2015-07-05 i 

E naturalmente address(dt1) deve corrispondere al address del magia dichiarazione.

+0

sorpreso che 'dt1 [dt2, val: = i.val, rotolo = -Inf]' non funziona (e non l'aggiunta, ad esempio, 'mult = "all"' o 'allow.cartesian = T'). .. sembra un FR. – MichaelChirico

+5

Stai cercando 'dt1 [, val: = dt2 [dt1, roll = TRUE] $ val]'? (Questo argomento è stato menzionato da Arun nel thread Github su questo argomento.) – Frank

risposta

3

Ecco un metodo che dovrebbe scalare.

address(dt1) 
# [1] "0x265a060" 
ix = dt2[dt1, roll=TRUE, which=TRUE] 
dt1[, val := dt2[ix, val]] 
dt1 
#   date val 
# 1: 2015-06-28 NA 
# 2: 2015-07-01 h 
# 3: 2015-07-03 h 
# 4: 2015-07-05 i 
address(dt1) 
# [1] "0x265a060" 

O senza la creazione dell'indice, direttamente come:

dt1[, val := dt2[dt1, val, roll = TRUE]] ## (1) 

Si noti che questo è più efficiente di fare:

dt1[, val := dt2[dt1, roll = TRUE]$val] ## (2) 

(2) esegue l'intero join (materializza tutto il colonne) e quindi estrae val, dove come (1) estrae direttamente la colonna val.

+0

Non vedo come sia diverso da ciò che è stato pubblicato nei commenti 6 ore fa. Il motivo per cui questo non è stato pubblicato come risposta è perché è stato già risolto su GH –

+2

@DavidArenburg che va bene. È una bella Q, e Jan ha chiesto qui su SO. – Arun

+0

@Arun Perché è una "soluzione alternativa"? –

1

Ecco una soluzione alternativa; Non perfetta perché coinvolge continuando a creare memoria aggiuntiva, anche se ci può essere un modo per evitare questo, che non viene a me subito (in ogni caso la memoria aggiuntiva può essere minima):

> address(dt1) 
[1] "0x57b5230" 

rng<-range(dt1[,range(date)],dt2[,range(date)]) 

x<-data.table(date=seq(from=rng[1],to=rng[2],by="day"), 
       key="date") 

> address(x) 
[1] "0x6aa2df0" 

x[dt2,setdiff(names(dt2),"date"):=mget(setdiff(names(dt2),"date")) 
    ][,val:=zoo::na.locf(val,na.rm=F)] 

> address(x) 
[1] "0x6aa2df0" 

> dt1[x,val:=i.val][] 
     date val 
1: 2015-06-28 NA 
2: 2015-07-01 h 
3: 2015-07-03 h 
4: 2015-07-05 i 

> address(dt1) 
[1] "0x57b5230" 
+0

Grazie per l'input, non è possibile accettare la risposta in quanto non è * per riferimento * - rendere la copia meno scalabile. E il focus della domanda era su quella particolare soluzione (rolling join e per riferimento) per avere la soluzione più scalabile. Inoltre penso che 'zoo :: na.locf' possa essere molto più costoso del rolling join di data.table. – jangorecki

+0

Non viene eseguita alcuna copia - 'x' viene creato con una colonna, quindi aggiornato per riferimento. Sono d'accordo che è probabilmente lento, ma il modo nativo per farlo dovrebbe essere stato 'dt1 [dt2, val: = i.val, roll = -Inf] ', a meno che mi manchi qualcosa. – MichaelChirico