Tengo un marco de datos y algunas columnas tienen NA
valores.
¿Cómo reemplazo estos NA
valores con ceros?
Tengo un marco de datos y algunas columnas tienen NA
valores.
¿Cómo reemplazo estos NA
valores con ceros?
Respuestas:
Vea mi comentario en la respuesta @ gsk3. Un simple ejemplo:
> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 3 NA 3 7 6 6 10 6 5
2 9 8 9 5 10 NA 2 1 7 2
3 1 1 6 3 6 NA 1 4 1 6
4 NA 4 NA 7 10 2 NA 4 1 8
5 1 2 4 NA 2 6 2 6 7 4
6 NA 3 NA NA 10 2 1 10 8 4
7 4 4 9 10 9 8 9 4 10 NA
8 5 8 3 2 1 4 5 9 4 7
9 3 9 10 1 9 9 10 5 3 3
10 4 2 2 5 NA 9 7 2 5 5
> d[is.na(d)] <- 0
> d
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 3 0 3 7 6 6 10 6 5
2 9 8 9 5 10 0 2 1 7 2
3 1 1 6 3 6 0 1 4 1 6
4 0 4 0 7 10 2 0 4 1 8
5 1 2 4 0 2 6 2 6 7 4
6 0 3 0 0 10 2 1 10 8 4
7 4 4 9 10 9 8 9 4 10 0
8 5 8 3 2 1 4 5 9 4 7
9 3 9 10 1 9 9 10 5 3 3
10 4 2 2 5 0 9 7 2 5 5
No hay necesidad de aplicar apply
. =)
EDITAR
También deberías echar un vistazo al norm
paquete. Tiene muchas características agradables para el análisis de datos faltantes. =)
df[19:28][is.na(df[19:28])] <- 0
Las opciones hibridadas dplyr ahora son alrededor de un 30% más rápidas que las reasignaciones del subconjunto Base R. En un marco de datos de punto de datos de 100Mmutate_all(~replace(., is.na(.), 0))
ejecuta medio segundo más rápido que la d[is.na(d)] <- 0
opción base R. Lo que uno quiere evitar específicamente es usar un ifelse()
o un if_else()
. (El análisis completo de 600 ensayos duró más de 4.5 horas debido principalmente a la inclusión de estos enfoques). Consulte los análisis de referencia a continuación para obtener los resultados completos.
Si está luchando con marcos de datos masivos, data.table
es la opción más rápida de todas: 40% más rápido que el enfoque estándar de Base R. También modifica los datos en el lugar, lo que le permite trabajar con casi el doble de datos a la vez.
Localmente:
mutate_at(c(5:10), ~replace(., is.na(.), 0))
mutate_at(vars(var5:var10), ~replace(., is.na(.), 0))
mutate_at(vars(contains("1")), ~replace(., is.na(.), 0))
contains()
, tratar ends_with()
,starts_with()
mutate_at(vars(matches("\\d{2}")), ~replace(., is.na(.), 0))
Condicionalmente:
(cambie solo un tipo y deje otros tipos solos).
mutate_if(is.integer, ~replace(., is.na(.), 0))
mutate_if(is.numeric, ~replace(., is.na(.), 0))
mutate_if(is.character, ~replace(., is.na(.), 0))
Actualizado para dplyr 0.8.0: las funciones usan ~
símbolos de formato purrr : reemplazando funs()
argumentos obsoletos .
# Base R:
baseR.sbst.rssgn <- function(x) { x[is.na(x)] <- 0; x }
baseR.replace <- function(x) { replace(x, is.na(x), 0) }
baseR.for <- function(x) { for(j in 1:ncol(x))
x[[j]][is.na(x[[j]])] = 0 }
# tidyverse
## dplyr
dplyr_if_else <- function(x) { mutate_all(x, ~if_else(is.na(.), 0, .)) }
dplyr_coalesce <- function(x) { mutate_all(x, ~coalesce(., 0)) }
## tidyr
tidyr_replace_na <- function(x) { replace_na(x, as.list(setNames(rep(0, 10), as.list(c(paste0("var", 1:10)))))) }
## hybrid
hybrd.ifelse <- function(x) { mutate_all(x, ~ifelse(is.na(.), 0, .)) }
hybrd.replace_na <- function(x) { mutate_all(x, ~replace_na(., 0)) }
hybrd.replace <- function(x) { mutate_all(x, ~replace(., is.na(.), 0)) }
hybrd.rplc_at.idx<- function(x) { mutate_at(x, c(1:10), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.nse<- function(x) { mutate_at(x, vars(var1:var10), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.stw<- function(x) { mutate_at(x, vars(starts_with("var")), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.ctn<- function(x) { mutate_at(x, vars(contains("var")), ~replace(., is.na(.), 0)) }
hybrd.rplc_at.mtc<- function(x) { mutate_at(x, vars(matches("\\d+")), ~replace(., is.na(.), 0)) }
hybrd.rplc_if <- function(x) { mutate_if(x, is.numeric, ~replace(., is.na(.), 0)) }
# data.table
library(data.table)
DT.for.set.nms <- function(x) { for (j in names(x))
set(x,which(is.na(x[[j]])),j,0) }
DT.for.set.sqln <- function(x) { for (j in seq_len(ncol(x)))
set(x,which(is.na(x[[j]])),j,0) }
DT.nafill <- function(x) { nafill(df, fill=0)}
DT.setnafill <- function(x) { setnafill(df, fill=0)}
library(microbenchmark)
# 20% NA filled dataframe of 10 Million rows and 10 columns
set.seed(42) # to recreate the exact dataframe
dfN <- as.data.frame(matrix(sample(c(NA, as.numeric(1:4)), 1e7*10, replace = TRUE),
dimnames = list(NULL, paste0("var", 1:10)),
ncol = 10))
# Running 600 trials with each replacement method
# (the functions are excecuted locally - so that the original dataframe remains unmodified in all cases)
perf_results <- microbenchmark(
hybrid.ifelse = hybrid.ifelse(copy(dfN)),
dplyr_if_else = dplyr_if_else(copy(dfN)),
hybrd.replace_na = hybrd.replace_na(copy(dfN)),
baseR.sbst.rssgn = baseR.sbst.rssgn(copy(dfN)),
baseR.replace = baseR.replace(copy(dfN)),
dplyr_coalesce = dplyr_coalesce(copy(dfN)),
tidyr_replace_na = tidyr_replace_na(copy(dfN)),
hybrd.replace = hybrd.replace(copy(dfN)),
hybrd.rplc_at.ctn= hybrd.rplc_at.ctn(copy(dfN)),
hybrd.rplc_at.nse= hybrd.rplc_at.nse(copy(dfN)),
baseR.for = baseR.for(copy(dfN)),
hybrd.rplc_at.idx= hybrd.rplc_at.idx(copy(dfN)),
DT.for.set.nms = DT.for.set.nms(copy(dfN)),
DT.for.set.sqln = DT.for.set.sqln(copy(dfN)),
times = 600L
)
> print(perf_results) Unit: milliseconds expr min lq mean median uq max neval hybrd.ifelse 6171.0439 6339.7046 6425.221 6407.397 6496.992 7052.851 600 dplyr_if_else 3737.4954 3877.0983 3953.857 3946.024 4023.301 4539.428 600 hybrd.replace_na 1497.8653 1706.1119 1748.464 1745.282 1789.804 2127.166 600 baseR.sbst.rssgn 1480.5098 1686.1581 1730.006 1728.477 1772.951 2010.215 600 baseR.replace 1457.4016 1681.5583 1725.481 1722.069 1766.916 2089.627 600 dplyr_coalesce 1227.6150 1483.3520 1524.245 1519.454 1561.488 1996.859 600 tidyr_replace_na 1248.3292 1473.1707 1521.889 1520.108 1570.382 1995.768 600 hybrd.replace 913.1865 1197.3133 1233.336 1238.747 1276.141 1438.646 600 hybrd.rplc_at.ctn 916.9339 1192.9885 1224.733 1227.628 1268.644 1466.085 600 hybrd.rplc_at.nse 919.0270 1191.0541 1228.749 1228.635 1275.103 2882.040 600 baseR.for 869.3169 1180.8311 1216.958 1224.407 1264.737 1459.726 600 hybrd.rplc_at.idx 839.8915 1189.7465 1223.326 1228.329 1266.375 1565.794 600 DT.for.set.nms 761.6086 915.8166 1015.457 1001.772 1106.315 1363.044 600 DT.for.set.sqln 787.3535 918.8733 1017.812 1002.042 1122.474 1321.860 600
ggplot(perf_results, aes(x=expr, y=time/10^9)) +
geom_boxplot() +
xlab('Expression') +
ylab('Elapsed Time (Seconds)') +
scale_y_continuous(breaks = seq(0,7,1)) +
coord_flip()
qplot(y=time/10^9, data=perf_results, colour=expr) +
labs(y = "log10 Scaled Elapsed Time per Trial (secs)", x = "Trial Number") +
coord_cartesian(ylim = c(0.75, 7.5)) +
scale_y_log10(breaks=c(0.75, 0.875, 1, 1.25, 1.5, 1.75, seq(2, 7.5)))
Cuando los conjuntos de datos se hacen más grandes, Tidyr '' s replace_na
se habían retirado históricamente hacia el frente. Con la colección actual de 100M puntos de datos para ejecutar, funciona casi exactamente tan bien como una Base R For Loop. Tengo curiosidad por ver qué sucede con los marcos de datos de diferentes tamaños.
Ejemplos adicionales para la mutate
e summarize
_at
y _all
variantes de función se pueden encontrar aquí: https://rdrr.io/cran/dplyr/man/summarise_all.html
Además, encontré manifestaciones votos y colecciones de ejemplos aquí: https: //blog.exploratory. io / dplyr-0-5-is-awesome-heres-why-be095fd4eb8a
Con especial agradecimiento a:
local()
, y (con la ayuda del paciente de Frank, también) el papel que juega la coerción silenciosa en acelerar muchos de estos enfoques. coalesce()
función más nueva y actualice el análisis.data.table
funciones lo suficientemente bien como para finalmente incluirlas en la alineación.is.numeric()
realmente prueba.(Por supuesto, comuníquese y deles votos positivos también si considera que esos enfoques son útiles).
Nota sobre mi uso de Numerics: si tiene un conjunto de datos entero puro, todas sus funciones se ejecutarán más rápido. Consulte el trabajo de alexiz_laz para obtener más información. IRL, no recuerdo haber encontrado un conjunto de datos que contiene más del 10-15% de enteros, por lo que estoy ejecutando estas pruebas en marcos de datos totalmente numéricos.
Hardware utilizado CPU de 3.9 GHz con 24 GB de RAM
df1[j][is.na(df1[j])] = 0
está mal, debería serdf1[[j]][is.na(df1[[j]])] = 0
forLp_Sbst
no parece ser una forma de que nadie debe tener en cuenta que se acerca vsforLp_smplfSbst
coalesce()
opción y la volví a ejecutar todas las veces. Gracias por el empujón para actualizar.
Para un solo vector:
x <- c(1,2,NA,4,5)
x[is.na(x)] <- 0
Para un data.frame, haga una función de lo anterior, luego apply
a las columnas.
Proporcione un ejemplo reproducible la próxima vez como se detalla aquí:
is.na
es una función genérica y tiene métodos para objetos de data.frame
clase. así que este también funcionará en data.frame
s!
methods(is.na)
por primera vez, estaba como whaaa?!? . ¡Me encanta cuando suceden cosas así! =)
Ejemplo de dplyr:
library(dplyr)
df1 <- df1 %>%
mutate(myCol1 = if_else(is.na(myCol1), 0, myCol1))
Nota: Estos trabajos por columna seleccionada, si tenemos que hacer esto para toda la columna, ver @reidjax 's respuesta usando mutate_each .
Sé que la pregunta ya está respondida, pero hacerlo de esta manera podría ser más útil para algunos:
Defina esta función:
na.zero <- function (x) {
x[is.na(x)] <- 0
return(x)
}
Ahora, siempre que necesite convertir NA en un vector a cero, puede hacer:
na.zero(some.vector)
Con dplyr
0.5.0, puede usar la coalesce
función que se puede integrar fácilmente en la %>%
tubería haciendo coalesce(vec, 0)
. Esto reemplaza todos los NA vec
con 0:
Digamos que tenemos un marco de datos con NA
s:
library(dplyr)
df <- data.frame(v = c(1, 2, 3, NA, 5, 6, 8))
df
# v
# 1 1
# 2 2
# 3 3
# 4 NA
# 5 5
# 6 6
# 7 8
df %>% mutate(v = coalesce(v, 0))
# v
# 1 1
# 2 2
# 3 3
# 4 0
# 5 5
# 6 6
# 7 8
Enfoque más general del uso replace()
en matriz o vector para reemplazar NA
a0
Por ejemplo:
> x <- c(1,2,NA,NA,1,1)
> x1 <- replace(x,is.na(x),0)
> x1
[1] 1 2 0 0 1 1
Esta es también una alternativa al uso ifelse()
endplyr
df = data.frame(col = c(1,2,NA,NA,1,1))
df <- df %>%
mutate(col = replace(col,is.na(col),0))
levels(A$x) <- append(levels(A$x), "notAnswered") A$x <- replace(A$x,which(is.na(A$x)),"notAnswered")
which
no es necesario aquí, puedes usarlo x1 <- replace(x,is.na(x),1)
.
NA
a 0
en sólo una columna específica de una trama de datos grande y esta función replace()
trabajado la manera más eficaz a la vez que el más simple.
Si desea reemplazar los NA en las variables de factor, esto podría ser útil:
n <- length(levels(data.vector))+1
data.vector <- as.numeric(data.vector)
data.vector[is.na(data.vector)] <- n
data.vector <- as.factor(data.vector)
levels(data.vector) <- c("level1","level2",...,"leveln", "NAlevel")
Transforma un vector factorial en un vector numérico y agrega otro nivel de factor numérico artificial, que luego se transforma de nuevo en un vector factorial con un "nivel NA" adicional de su elección.
Hubiera comentado en la publicación de @ ianmunoz pero no tengo suficiente reputación. Se pueden combinar dplyr
's mutate_each
y replace
cuidar de la NA
de 0
reemplazo. Usando el marco de datos de la respuesta de @ aL3xa ...
> m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
> d <- as.data.frame(m)
> d
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 8 1 9 6 9 NA 8 9 8
2 8 3 6 8 2 1 NA NA 6 3
3 6 6 3 NA 2 NA NA 5 7 7
4 10 6 1 1 7 9 1 10 3 10
5 10 6 7 10 10 3 2 5 4 6
6 2 4 1 5 7 NA NA 8 4 4
7 7 2 3 1 4 10 NA 8 7 7
8 9 5 8 10 5 3 5 8 3 2
9 9 1 8 7 6 5 NA NA 6 7
10 6 10 8 7 1 1 2 2 5 7
> d %>% mutate_each( funs_( interp( ~replace(., is.na(.),0) ) ) )
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1 4 8 1 9 6 9 0 8 9 8
2 8 3 6 8 2 1 0 0 6 3
3 6 6 3 0 2 0 0 5 7 7
4 10 6 1 1 7 9 1 10 3 10
5 10 6 7 10 10 3 2 5 4 6
6 2 4 1 5 7 0 0 8 4 4
7 7 2 3 1 4 10 0 8 7 7
8 9 5 8 10 5 3 5 8 3 2
9 9 1 8 7 6 5 0 0 6 7
10 6 10 8 7 1 1 2 2 5 7
Aquí estamos utilizando la evaluación estándar (SE), por lo que necesitamos el guión bajo en " funs_
." También usamos lazyeval
's interp
/ ~
y las .
referencias "todo con lo que estamos trabajando", es decir, el marco de datos. ¡Ahora hay ceros!
Puedes usar replace()
Por ejemplo:
> x <- c(-1,0,1,0,NA,0,1,1)
> x1 <- replace(x,5,1)
> x1
[1] -1 0 1 0 1 0 1 1
> x1 <- replace(x,5,mean(x,na.rm=T))
> x1
[1] -1.00 0.00 1.00 0.00 0.29 0.00 1.00 1.00
NA
s en su vector. Está bien para vectores pequeños como en su ejemplo.
x1 <- replace(x,is.na(x),1)
funcionará sin enumerar explícitamente los valores del índice.
Otra dplyr
opción compatible con tubería con tidyr
método replace_na
que funciona para varias columnas:
require(dplyr)
require(tidyr)
m <- matrix(sample(c(NA, 1:10), 100, replace = TRUE), 10)
d <- as.data.frame(m)
myList <- setNames(lapply(vector("list", ncol(d)), function(x) x <- 0), names(d))
df <- d %>% replace_na(myList)
Puede restringir fácilmente, por ejemplo, a las columnas numéricas:
d$str <- c("string", NA)
myList <- myList[sapply(d, is.numeric)]
df <- d %>% replace_na(myList)
La función dedicada ( nafill
/ setnafill
) para ese propósito está en la data.table
versión reciente
install.packages("data.table", repos="https://Rdatatable.gitlab.io/data.table")
library(data.table)
ans_df = nafill(df, fill=0)
setnafill(df, fill=0) # this one updates in-place
Para reemplazar todas las NA en un marco de datos, puede usar:
df %>% replace(is.na(.), 0)
si desea asignar un nuevo nombre después de cambiar los NA en una columna específica en este caso la columna V3, use también puede hacer esto
my.data.frame$the.new.column.name <- ifelse(is.na(my.data.frame$V3),0,1)