Cómo reemplazar los valores NA en una tabla para columnas seleccionadas


82

Hay muchas publicaciones sobre cómo reemplazar los valores de NA. Soy consciente de que se podrían reemplazar las NA en la siguiente tabla / marco con lo siguiente:

x[is.na(x)]<-0

Pero, ¿qué pasa si quiero restringirlo solo a ciertas columnas? Déjame mostrarte un ejemplo.

Primero, comencemos con un conjunto de datos.

set.seed(1234)
x <- data.frame(a=sample(c(1,2,NA), 10, replace=T),
                b=sample(c(1,2,NA), 10, replace=T), 
                c=sample(c(1:5,NA), 10, replace=T))

Lo que da:

    a  b  c
1   1 NA  2
2   2  2  2
3   2  1  1
4   2 NA  1
5  NA  1  2
6   2 NA  5
7   1  1  4
8   1  1 NA
9   2  1  5
10  2  1  1

Ok, entonces solo quiero restringir el reemplazo a las columnas 'a' y 'b'. Mi intento fue:

x[is.na(x), 1:2]<-0

y:

x[is.na(x[1:2])]<-0

Que no funciona.

Mi intento de data.table, donde y<-data.table(x), obviamente, nunca iba a funcionar:

y[is.na(y[,list(a,b)]), ]

Quiero pasar columnas dentro del argumento is.na, pero eso obviamente no funcionaría.

Me gustaría hacer esto en un data.frame y un data.table. Mi objetivo final es recodificar el 1: 2 a 0: 1 en 'a' y 'b' manteniendo 'c' como está, ya que no es una variable lógica. Tengo un montón de columnas, así que no quiero hacerlo una por una. Y me gustaría saber cómo hacer esto.

¿Tienes alguna sugerencia?

Respuestas:


115

Tu puedes hacer:

x[, 1:2][is.na(x[, 1:2])] <- 0

o mejor (en mi humilde opinión), use los nombres de las variables:

x[c("a", "b")][is.na(x[c("a", "b")])] <- 0

En ambos casos, 1:2o c("a", "b")puede ser reemplazado por un vector predefinido.


Eso hace el trabajo. ¿Qué pasa si quiero buscar "1"? Traté de cambiarlo pero no pude hacer que funcionara.
jnam27

5
Probablemente así:x[, 1:2][x[, 1:2] == 1] <- 0
flodel

@flodel, ¿por qué la tabla de datos xacepta una matriz como su primer miembro solo cuando se realiza la asignación? ¿Esta característica está documentada en alguna parte? También creo que olvidó poner una coma antes de los vectores con los nombres de las columnas en su segundo ejemplo.
ChiseledAbs

@ChiseledAbs, creo que se está refiriendo a la indexación matricial (consulte esto, por ejemplo, stackoverflow.com/a/13999583/1201032 ), pero no se limita a las asignaciones, también se puede usar para extraer datos. Respecto a la coma faltante: no. Los marcos de datos son listas de columnas, por lo que si usa un solo argumento [, extraerá las columnas especificadas (consulte stackoverflow.com/a/21137524/1201032 ). Espero que esto responda a su pregunta, pero en el futuro, evite comentar sobre respuestas muy antiguas como esta; en su lugar, publique una nueva pregunta.
Flodel

In both cases, 1:2 or c("a", "b") can be replaced by a pre-defined vector.Cuando utilicé un vector predefinido como este x[Vpredefined][is.na(x[Vpredefined])] <- 0, me dio un error
Rohit Saluja

30

Editar 2020-06-15

Desde data.table1.12.4 (octubre de 2019), data.tableobtiene dos funciones para facilitar esto: nafilly setnafill.

nafill opera en columnas:

cols = c('a', 'b')
y[ , (cols) := lapply(.SD, nafill, fill=0), .SDcols = cols]

setnafill opera en tablas (los reemplazos ocurren por referencia / en el lugar)

setnafill(y, cols=cols, fill=0)
# print y to show the effect
y[]

Esto también será más eficiente que las otras opciones; Para ?nafillobtener más información, consulte las versiones de NAimputación de la última observación trasladada hacia adelante (LOCF) y la siguiente observación trasladada hacia atrás (NOCB) para series de tiempo.


Esto funcionará para su data.tableversión:

for (col in c("a", "b")) y[is.na(get(col)), (col) := 0]

Alternativamente, como señala David Arenburg a continuación, puede usar set(beneficio adicional: puede usarlo en data.frameo data.table):

for (col in 1:2) set(x, which(is.na(x[[col]])), col, 0)

gracias por esto. Solo quería saber, 3 años después, si hay formas de hacer lo anterior sin un bucle for. Me imagino que el equipo de data.table habría hecho esto más conciso. Gracias.
info_seekeR

1
@info_seekeR No conozco una forma más concisa
eddi

esta es una mejor solución que la respuesta seleccionada por flodel. El enfoque de Flodel utiliza el operador de asignación <y, por lo tanto, implica una copia de datos innecesaria.
Michael

@MichaelChirico En la primera parte de su comentario, ¿agregó el paso out <- xpara evitar malentendidos con el x data.frame de la pregunta? De lo contrario, este es un comando aún más corto: y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]omitir el nombre de la variable 'out' y el uso de 'x'.
Yoann Pageaud

@MichaelChirico ¡Cierto! Me olvidé por completo de nafill ()
Yoann Pageaud

21

Sobre la base de la tidyr::replace_na()respuesta de @Robert McDonald's , aquí hay algunas dplyropciones para controlar qué columnas NAse reemplazan las s:

library(tidyverse)

# by column type:
x %>%
  mutate_if(is.numeric, ~replace_na(., 0))

# select columns defined in vars(col1, col2, ...):
x %>%
  mutate_at(vars(a, b, c), ~replace_na(., 0))

# all columns:
x %>%
  mutate_all(~replace_na(., 0))

1
Con esta función se produce el error: Error in replace_na(., 0) : argument "value" is missing, with no default. ¿Alguna sugerencia de qué cambiar?
Tim M. Schendzielorz

17

Esto ahora es trivial en tidyr con replace_na (). La función parece funcionar tanto para data.tables como para data.frames:

tidyr::replace_na(x, list(a=0, b=0))

2

No estoy seguro si esto es más conciso, pero esta función también encontrará y permitirá el reemplazo de NA (o cualquier valor que desee) en columnas seleccionadas de una tabla de datos:

update.mat <- function(dt, cols, criteria) {
  require(data.table)
  x <- as.data.frame(which(criteria==TRUE, arr.ind = TRUE))
  y <- as.matrix(subset(x, x$col %in% which((names(dt) %in% cols), arr.ind = TRUE)))
  y
}

Para aplicarlo:

y[update.mat(y, c("a", "b"), is.na(y))] <- 0

La función crea una matriz de las columnas y filas seleccionadas (coordenadas de celda) que cumplen con los criterios de entrada (en este caso es.na == VERDADERO).


1

Podemos resolverlo de data.tablemanera con tidyr::repalce_nafunción ylapply

library(data.table)
library(tidyr)
setDT(df)
df[,c("a","b","c"):=lapply(.SD,function(x) replace_na(x,0)),.SDcols=c("a","b","c")]

De esta forma, también podemos resolver pegar columnas con NAstring. ¡Primero, nosotros replace_na(x,""), luego podemos usar stringr::str_cpara combinar columnas!


1
Gracias por este fragmento de código, que puede proporcionar ayuda inmediata y limitada. Una explicación adecuada mejoraría enormemente su valor a largo plazo al mostrar por qué es una buena solución al problema y lo haría más útil para futuros lectores con otras preguntas similares. Por favor, editar su respuesta a añadir un poco de explicación, incluyendo los supuestos realizados.
CertainPerformance

0

Para una columna específica, existe una alternativa con sapply

DF <- data.frame(A = letters[1:5],
             B = letters[6:10],
             C = c(2, 5, NA, 8, NA))

DF_NEW <- sapply(seq(1, nrow(DF)),
                    function(i) ifelse(is.na(DF[i,3]) ==
                                       TRUE,
                                       0,
                                       DF[i,3]))

DF[,3] <- DF_NEW
DF

0

es bastante útil con {data.table} y {stringr}

library(data.table)
library(stringr)

x[, lapply(.SD, function(xx) {str_replace_na(xx, 0)})]

FYI


0

A partir de data.table y, puede escribir:
y[, (cols):=lapply(.SD, function(i){i[is.na(i)] <- 0; i}), .SDcols = cols]
No se olvide library(data.table)antes de crear yy ejecutar este comando.


-4

Esto funciona bien para mi

DataTable DT = new DataTable();

DT = DT.AsEnumerable().Select(R =>
{
      R["Campo1"] = valor;
      return (R);
}).ToArray().CopyToDataTable();

1
es esta R? parece C #
Chris McKelt
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.