Ultima osservazione effettuata in avanti in un frame di dati?

Desidero implementare un ‘”Ultima osservazione effettuata” per un set di dati su cui sto lavorando e che alla fine ha valori mancanti.

Ecco un semplice codice per farlo (domanda dopo):

LOCF <- function(x) { # Last Observation Carried Forward (for a left to right series) LOCF <- max(which(!is.na(x))) # the location of the Last Observation to Carry Forward x[LOCF:length(x)] <- x[LOCF] return(x) } # example: LOCF(c(1,2,3,4,NA,NA)) LOCF(c(1,NA,3,4,NA,NA)) 

Ora funziona alla grande per i vettori semplici. Ma se io dovessi provare ad usarlo su un frame di dati:

 a <- data.frame(rep("a",4), 1:4,1:4, c(1,NA,NA,NA)) a t(apply(a, 1, LOCF)) # will make a mess 

Trasformsrà il mio frame di dati in una matrice di caratteri.

Riesci a pensare a un modo di fare LOCF su un data.frame, senza trasformarlo in una matrice? (Potrei usare loop e simili per correggere il disordine, ma mi piacerebbe una soluzione più elegante)

Saluti,

Tal

Questo esiste già:

 library(zoo) na.locf(data.frame(rep("a",4), 1:4,1:4, c(1,NA,NA,NA))) 

Se non vuoi caricare un grande pacchetto come zoo solo per la funzione na.locf, ecco una soluzione breve che funziona anche se ci sono alcuni NA leader nel vettore di input.

 na.locf <- function(x) { v <- !is.na(x) c(NA, x[v])[cumsum(v)+1] } 

Aggiunta della nuova funzione tidyr::fill() per portare avanti l’ultima osservazione in una colonna per compilare NA s:

 a <- data.frame(col1 = rep("a",4), col2 = 1:4, col3 = 1:4, col4 = c(1,NA,NA,NA)) a # col1 col2 col3 col4 # 1 a 1 1 1 # 2 a 2 2 NA # 3 a 3 3 NA # 4 a 4 4 NA a %>% tidyr::fill(col4) # col1 col2 col3 col4 # 1 a 1 1 1 # 2 a 2 2 1 # 3 a 3 3 1 # 4 a 4 4 1 

Ci sono un sacco di pacchetti che implementano esattamente questa funzionalità. (con le stesse funzionalità di base, ma alcune differenze nelle opzioni aggiuntive)

  • spazio-tempo :: na.locf
  • imputeTS :: na.locf
  • zoo :: na.locf
  • XTS :: na.locf

Questa domanda è vecchia ma per i posteri … la soluzione migliore è usare il pacchetto data.table con il roll = T.

Ho finito per risolverlo usando un loop:

 fillInTheBlanks <- function(S) { L <- !is.na(S) c(S[L][1], S[L])[cumsum(L)+1] } LOCF.DF <- function(xx) { # won't work well if the first observation is NA orig.class <- lapply(xx, class) new.xx <- data.frame(t( apply(xx,1, fillInTheBlanks) )) for(i in seq_along(orig.class)) { if(orig.class[[i]] == "factor") new.xx[,i] <- as.factor(new.xx[,i]) if(orig.class[[i]] == "numeric") new.xx[,i] <- as.numeric(new.xx[,i]) if(orig.class[[i]] == "integer") new.xx[,i] <- as.integer(new.xx[,i]) } #t(na.locf(t(a))) return(new.xx) } a <- data.frame(rep("a",4), 1:4,1:4, c(1,NA,NA,NA)) LOCF.DF(a) 

Invece di apply() puoi usare lapply() e quindi trasformare la lista risultante in data.frame .

 LOCF <- function(x) { # Last Observation Carried Forward (for a left to right series) LOCF <- max(which(!is.na(x))) # the location of the Last Observation to Carry Forward x[LOCF:length(x)] <- x[LOCF] return(x) } a <- data.frame(rep("a",4), 1:4, 1:4, c(1, NA, NA, NA)) a data.frame(lapply(a, LOCF))