2016-01-03 26 views
5

Attribuite vari a fila XTS oggetti:Come unire oggetti xts con colonne leggermente diverse?

z1 = xts(t(c("9902"=0,"9903"=0,"9904"=0,"9905"=2,"9906"=2)),as.Date("2015-01-01")) 
z2 = xts(t(c("9902"=3,"9903"=4,"9905"=6,"9906"=5,"9908"=8)),as.Date("2015-01-02")) 
z3 = xts(t(c("9901"=1,"9903"=3,"9905"=5,"9906"=6,"9907"=7,"9909"=9)),as.Date("2015-01-03")) 

voglio unirli in un unico oggetto XTS. Ma cbind(z1,z2,z3) dà:

  X9902 X9903 X9904 X9905 X9906 X9902.1 X9903.1 X9905.1 X9906.1 X9908 X9901 X9903.2 X9905.2 X9906.2 X9907 X9909 
2015-01-01  0  0  0  2  2  NA  NA  NA  NA NA NA  NA  NA  NA NA NA 
2015-01-02 NA NA NA NA NA  3  4  6  5  8 NA  NA  NA  NA NA NA 
2015-01-03 NA NA NA NA NA  NA  NA  NA  NA NA  1  3  5  6  7  9 

Mentre quello che mi aspetto è:

  9901 9902 9903 9904 9905 9906 9907 9908 9909 
2015-01-01 0 0 0 0 2 2 0 0 0 
2015-01-02 0 3 4 0 6 5 0 8 0 
2015-01-03 1 0 3 0 5 6 7 0 9 

(. Posso ottenere le AN cambiato zeri con dare fill=0, cioè cbind(z1,z2,z3,fill=0))

rbind(z1,z2,z3) lamenta che le righe avere un numero diverso di colonne. Ma, credo che se le colonne mancanti fossero aggiunte a ciascun oggetto xts in anticipo, questo sarebbe un buon approccio?

I dati reali possono avere migliaia di righe e alcune centinaia di colonne (una volta unite), quindi ho un occhio sull'efficienza.

+0

'' merge.xts' e merge.zoo' unire solo per indice, quindi non è possibile ottenere il risultato desiderato usando 'merge' (o' cbind'). Quindi sembra che tu abbia bisogno di 'rbind', ma (come dici tu) richiederà che tutti gli oggetti abbiano lo stesso numero di colonne nello stesso ordine. –

risposta

4

Come ho detto nel mio commento, merge.xts (e merge.zoo) si uniscono solo per indice, quindi non è possibile ottenere il risultato desiderato utilizzando merge (o cbind). Quindi sembra che tu abbia bisogno di rbind, ma (come dici tu) richiederà che tutti gli oggetti abbiano lo stesso numero di colonne nello stesso ordine.

Ho creato due funzioni di seguito per aiutare a elaborare gli oggetti in modo che tu possa rbind per creare il risultato desiderato.

# put all xts objects in a list for easier processing 
x <- list(z1, z2, z3) 

# function to create template xts object 
template <- function(xlist) { 
    # find set of unique column names from all objects 
    cn <- unique(unlist(lapply(xlist, colnames))) 
    # create template xts object 
    # using a date that doesn't occur in the actual data 
    minIndex <- do.call(min, lapply(xlist, function(x) index(x[1L,]))) 
    # template object 
    xts(matrix(0,1,length(cn)), minIndex-1, dimnames=list(NULL, sort(cn))) 
} 

# function to apply to each xts object 
proc <- function(x, template) { 
    # columns we need to add 
    neededCols <- !(colnames(template) %in% colnames(x)) 
    # merge this object with template object, filling w/zeros 
    out <- merge(x, template[,neededCols], fill=0) 
    # reorder columns (NB: merge.xts always uses make.names) 
    # and remove first row (from template) 
    out <- out[-1L,make.names(colnames(template))] 
    # set column names back to desired values 
    # (using attr<- because dimnames<-.xts copies) 
    attr(out, "dimnames") <- list(NULL, colnames(template)) 
    # return object 
    out 
} 
(res <- do.call(rbind, lapply(x, proc, template=template(x)))) 
#   9901 9902 9903 9904 9905 9906 9907 9908 9909 
# 2015-01-01 0 0 0 0 2 2 0 0 0 
# 2015-01-02 0 3 4 0 6 5 0 8 0 
# 2015-01-03 1 0 3 0 5 6 7 0 9 
+0

Grazie; Penso che andrò con questo. Pensi che ci sarebbe una differenza significativa nelle prestazioni per creare una enorme matrice vuota in primo piano e copiarne il risultato, rispetto al rifare ogni oggetto xts, quindi chiamare rbind? (Dato che le matrici in R sono ordinate per colonna, suppongo che rbind abbia bisogno di fare quel tipo di copia, comunque?) –

+1

@DarrenCook: Non in cima alla mia testa. Potrebbe essere più veloce, ma dovrei profilo per verificare in entrambi i modi. 'rbind' fa quel tipo di copia, ma può usare' memcopy', che di solito è più veloce di chiamare le funzioni R. –

1
library(xts) 
library(plyr) 

z1df <- as.data.frame(z1) 
z2df <- as.data.frame(z2) 
z3df <- as.data.frame(z3) 

res <- rbind.fill(z1df, z2df, z3df) 
res[is.na(res)] <- 0 
res 

# 9902 9903 9904 9905 9906 9908 9901 9907 9909 
#1 0 0 0 2 2 0 0 0 0 
#2 3 4 0 6 5 8 0 0 0 
#3 0 3 0 5 6 0 1 7 9 

Questo è simile alla seguente post StackOverflow

combining two data frames of different lengths

includere la colonna data

res$Date <- c("2015-01-01", "2015-01-02", "2015-01-03") # the appropriate values 
res$Date <- as.Date(res$Date) 

e di trasformare per XTS oggetto

xts(res[,-10], order.by=res[,10]) 
+2

'rbind.fill' non è in xts. Anche il tuo risultato non è un oggetto xts. –

+0

@JoshuaUlrich Grazie. – steveb

+0

La soluzione aggiornata presuppone che i tempi in ciascun oggetto siano sequenziali e non sovrapposti, il che probabilmente non è il caso. Applicato ai dati effettivi, probabilmente assegnerebbe le date sbagliate a ciascuna riga. –