Última observación realizada en un dataframe?

Deseo implementar una “Última observación realizada” para un conjunto de datos en el que estoy trabajando y al que le faltan valores al final.

Aquí hay un código simple para hacerlo (pregunta después):

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)) 

Ahora esto funciona muy bien para vectores simples. Pero si bash usarlo en un dataframe:

 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 

Convertirá mi dataframe en una matriz de caracteres.

¿Puedes pensar en una forma de hacer LOCF en un data.frame, sin convertirlo en una matriz? (Podría usar bucles para corregir el problema, pero me encantaría una solución más elegante)

Aclamaciones,

Tal

Esto ya existe:

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

Si no desea cargar un paquete grande como zoo solo para la función na.locf, aquí hay una solución corta que también funciona si hay algunas NA principales en el vector de entrada.

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

Agregar la nueva función tidyr::fill() para llevar adelante la última observación en una columna para completar 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 

Hay muchos paquetes que implementan exactamente esta funcionalidad. (con la misma funcionalidad básica, pero algunas diferencias en las opciones adicionales)

  • espacio-tiempo :: na.locf
  • imputeTS :: na.locf
  • zoo :: na.locf
  • xts :: na.locf

Esta pregunta es antigua pero para la posteridad … la mejor solución es usar el paquete data.table con el rollo = T.

Terminé resolviendo esto usando un bucle:

 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) 

En lugar de apply() puede usar lapply() y luego transformar la lista resultante en 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)) 
    Intereting Posts