with values studio remove missing data check cases r dataframe missing-data r-factor

values - Cómo llenar NA con LOCF por factores en el marco de datos, dividido por país



remove na in r data frame (8)

Tengo el siguiente marco de datos (simplificado) con la variable de país como factor y la variable de valor tiene valores perdidos:

country value AUT NA AUT 5 AUT NA AUT NA GER NA GER NA GER 7 GER NA GER NA

Lo siguiente genera el marco de datos anterior:

data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA))

Ahora, me gustaría reemplazar los valores de NA en cada subconjunto de países utilizando el método de última observación llevada a cabo (LOCF). Conozco el comando na.locf en el paquete del zoo . data <- na.locf(data) me daría el siguiente marco de datos:

country value AUT NA AUT 5 AUT 5 AUT 5 GER 5 GER 5 GER 7 GER 7 GER 7

Sin embargo, la función solo debe utilizarse en los subconjuntos individuales divididos por el país . La siguiente es la salida que necesitaría:

country value AUT NA AUT 5 AUT 5 AUT 5 GER NA GER NA GER 7 GER 7 GER 7

No puedo pensar en una manera fácil de implementarlo. Antes de comenzar con for-loops, me preguntaba si alguien tiene alguna idea de cómo resolver esto.

¡¡Muchas gracias!!


Aquí hay una solución ddply . Prueba esto

library(plyr) ddply(DF, .(country), na.locf) country value 1 AUT <NA> 2 AUT 5 3 AUT 5 4 AUT 5 5 GER <NA> 6 GER <NA> 7 GER 7 8 GER 7 9 GER 7

Editar De ayuda ddply puede encontrar que

.variables: variables to split data frame by, as quoted variables, a formula or character vector.

Así que otras alternativas para conseguir lo que quieres son:

ddply(DF, "country", na.locf) ddply(DF, ~country, na.locf)

tenga en cuenta que no se permite reemplazar .variables con la DF$variable , por eso se produjo un error al hacer esto.

DF es tu data.frame


Divida el data.frame con by y use na.locf en los subconjuntos:

do.call(rbind,by(data,data$country,na.locf))

Si desea eliminar los nombres de las filas:

do.call(rbind,unname(by(data,data$country,na.locf)))


La forma tidyverse, aunque no usa locf, es:

library(tidyverse) data %>% group_by(country) %>% fill(value) Source: local data frame [9 x 2] Groups: country [2] country value (fctr) (dbl) 1 AUT NA 2 AUT 5 3 AUT 5 4 AUT 5 5 GER NA 6 GER NA 7 GER 7 8 GER 7 9 GER 7


Si la velocidad es una consideración, entonces esta unstack para unstack / stack es aproximadamente 4 a 6 veces más rápida que las otras en mi sistema, aunque conlleva una línea de código ligeramente más larga:

stack(lapply(unstack(data, value ~ country), na.locf, na.rm = FALSE))

Otro enfoque es:

transform(data, value = ave(value, country, FUN = na.locf0))


Simplemente necesita dividir por país, luego hacer un zoo::na.locf() o na.fill, llenando a la derecha. Aquí hay un ejemplo que muestra explícitamente la sintaxis arg de tres componentes de na.fill:

library(plyr) library(zoo) data <- data.frame(country=c("AUT", "AUT", "AUT", "AUT", "GER", "GER", "GER", "GER", "GER"), value=c(NA, 5, NA, NA, NA, NA, 7, NA, NA)) # The following is equivalent to na.locf na.fill.right <- function(...) { na.fill(..., list(left=NA,interior=NA,right="extend")) } ddply(data, .(country), na.fill.right) country value 1 AUT <NA> 2 AUT 5 3 AUT 5 4 AUT 5 5 GER <NA> 6 GER <NA> 7 GER 7 8 GER 7 9 GER 7


Una combinación de los paquetes dplyr e imputeTS puede hacer el trabajo.

library(dplyr) library(imputeTS) data %>% group_by(country) %>% mutate(value = na.locf(value, na.remaining="keep"))

Con el parámetro na.remaining de la función na.locf de imputeTS , tiene además la opción de elegir qué hacer con los NA finales.

Estas son las opciones:

  • "mantener" - devuelve la serie con NA
  • "rm" - elimina las NA restantes
  • "media": reemplaza las NA restantes por la media general
  • "rev" - ejecuta nocb / locf desde la dirección inversa

Al elegir "media", por ejemplo, obtendría un resultado con 7 por cada GER en el ejemplo específico.


Una versión moderna de la solución ddply es usar el paquete dplyr :

library(dplyr) DF %>% group_by(county) %>% mutate(value = na.locf(value, na.rm = F))


data.table un poco tarde a esta conversación, pero aquí hay una data.table , que será mucho más rápida para conjuntos de datos más grandes:

library(zoo) library(data.table) # Convert to data table setDT(data) data[, value := na.locf(value, na.rm = FALSE), by = country] data country value 1: AUT NA 2: AUT 5 3: AUT 5 4: AUT 5 5: GER NA 6: GER NA 7: GER 7 8: GER 7 9: GER 7 # And if you want to convert "data" back to a data frame... setDF(data)