Reemplace todos los valores 0 a NA

144

Tengo un marco de datos con algunas columnas numéricas. Algunas filas tienen un valor 0 que debe considerarse nulo en el análisis estadístico. ¿Cuál es la forma más rápida de reemplazar todo el valor 0 a NULL en R?

Visto
fuente
17
No creo que quiera / pueda reemplazar con valores NULL, pero NA cumple ese propósito en Ringo.
Chase

Respuestas:

243

Sustitución de todos los ceros a NA:

df[df == 0] <- NA



Explicación

1. No es NULLlo que debe reemplazar con ceros. Como se dice en ?'NULL',

NULL representa el objeto nulo en R

que es único y, supongo, puede verse como el objeto menos informativo y vacío. 1 Entonces no es tan sorprendente que

data.frame(x = c(1, NULL, 2))
#   x
# 1 1
# 2 2

Es decir, R no reserva ningún espacio para este objeto nulo. 2 Mientras tanto, mirando ?'NA'vemos que

NA es una constante lógica de longitud 1 que contiene un indicador de valor faltante. NA puede ser coaccionado a cualquier otro tipo de vector excepto raw.

Es importante destacar que NAes de longitud 1, por lo que R le reserva algo de espacio. P.ej,

data.frame(x = c(1, NA, 2))
#    x
# 1  1
# 2 NA
# 3  2

Además, la estructura del marco de datos requiere que todas las columnas tengan el mismo número de elementos para que no pueda haber "agujeros" (es decir, NULLvalores).

Ahora podría reemplazar ceros NULLen un marco de datos en el sentido de eliminar completamente todas las filas que contienen al menos un cero. Cuando se utiliza, por ejemplo, var, cov, o cor, que en realidad es equivalente a la sustitución de primera ceros con NAy estableciendo el valor de usetan "complete.obs". Por lo general, sin embargo, esto no es satisfactorio, ya que conduce a la pérdida de información adicional.

2. En lugar de ejecutar algún tipo de bucle, en la solución uso la df == 0vectorización. df == 0devuelve (pruébelo) una matriz del mismo tamaño que df, con las entradas TRUEy FALSE. Además, también se nos permite pasar esta matriz al subconjunto [...](ver ?'['). Por último, si bien el resultado df[df == 0]es perfectamente intuitivo, puede parecer extraño que df[df == 0] <- NAproduzca el efecto deseado. De <-hecho, el operador de asignación no siempre es tan inteligente y no funciona de esta manera con otros objetos, pero lo hace con marcos de datos; ver ?'<-'.


1 El conjunto vacío en la teoría de conjuntos se siente de alguna manera relacionado.
2 Otra similitud con la teoría de conjuntos: el conjunto vacío es un subconjunto de cada conjunto, pero no le reservamos ningún espacio.

Julius Vainora
fuente
3
¿Cuál sería la sintaxis equivalente para un objeto data.table?
itpetersen
66
Veo que ha obtenido muchos votos, pero no creo que esto cubra adecuadamente los casos límite de columnas no numéricas con valores de "0" que no se solicitó que se establecieran en <NA>.
IRTFM
33

Déjame asumir que tu data.frame es una mezcla de diferentes tipos de datos y no todas las columnas necesitan ser modificadas.

para modificar solo las columnas 12 a 18 (del total de 21), solo haga esto

df[, 12:18][df[, 12:18] == 0] <- NA
userJT
fuente
Esto funciona para mí, mientras que la respuesta aceptada no
Patrick Coulombe
23

Una forma alternativa sin la [<-función:

Un marco de datos de muestra dat(copiado descaradamente de la respuesta de @ Chase):

dat

  x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

Los ceros se pueden reemplazar NApor la is.na<-función:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA
Sven Hohenstein
fuente
22

dplyr::na_if() es una opción:

library(dplyr)  

df <- data_frame(col1 = c(1, 2, 3, 0),
                 col2 = c(0, 2, 3, 4),
                 col3 = c(1, 0, 3, 0),
                 col4 = c('a', 'b', 'c', 'd'))

na_if(df, 0)
# A tibble: 4 x 4
   col1  col2  col3 col4 
  <dbl> <dbl> <dbl> <chr>
1     1    NA     1 a    
2     2     2    NA b    
3     3     3     3 c    
4    NA     4    NA d
sbha
fuente
14
#Sample data
set.seed(1)
dat <- data.frame(x = sample(0:2, 5, TRUE), y = sample(0:2, 5, TRUE))
#-----
  x y
1 0 2
2 1 2
3 1 1
4 2 1
5 0 0

#replace zeros with NA
dat[dat==0] <- NA
#-----
   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA
Persecución
fuente
12

Debido a que alguien solicitó la versión Data.Table de esto, y porque la solución data.frame dada no funciona con data.table, proporciono la solución a continuación.

Básicamente, use el :=operador ->DT[x == 0, x := NA]

library("data.table")

status = as.data.table(occupationalStatus)

head(status, 10)
    origin destination  N
 1:      1           1 50
 2:      2           1 16
 3:      3           1 12
 4:      4           1 11
 5:      5           1  2
 6:      6           1 12
 7:      7           1  0
 8:      8           1  0
 9:      1           2 19
10:      2           2 40


status[N == 0, N := NA]

head(status, 10)
    origin destination  N
 1:      1           1 50
 2:      2           1 16
 3:      3           1 12
 4:      4           1 11
 5:      5           1  2
 6:      6           1 12
 7:      7           1 NA
 8:      8           1 NA
 9:      1           2 19
10:      2           2 40
Reilstein
fuente
2
O for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Vea aquí una discusión más detallada sobre el uso de data.table para buscar y reemplazar valores.
JWilliman
4

Puede reemplazar 0con NAsolo en campos numéricos (es decir, excluyendo cosas como factores), pero funciona columna por columna:

col[col == 0 & is.numeric(col)] <- NA

Con una función, puede aplicar esto a todo su marco de datos:

changetoNA <- function(colnum,df) {
    col <- df[,colnum]
    if (is.numeric(col)) {  #edit: verifying column is numeric
        col[col == -1 & is.numeric(col)] <- NA
    }
    return(col)
}
df <- data.frame(sapply(1:5, changetoNA, df))

Aunque podría reemplazar el 1:5con el número de columnas en su marco de datos, o con 1:ncol(df).

Alium Britt
fuente
No estoy seguro de que esta sea la solución correcta. ¿Qué pasa con las columnas 6 y más? Se cortarán.
userJT
Eso es por lo que sugirió reemplazar 1:5con 1:ncol(df)al final. No quería que la ecuación fuera demasiado compleja o difícil de leer.
Alium Britt
pero ¿qué pasa si en las columnas 6 y 7? el tipo de datos es char y no se debe hacer ningún reemplazo. En mi problema, necesito reemplazo solo en las columnas 12 a 15, pero todo el df tiene 21 columnas (muchas no deben tocarse en absoluto).
userJT
Para su trama de datos puede simplemente cambiar el 1:5que los números de las columnas que quieren cambiar, al igual 12:15, pero si quería que confirmar que sólo afectará a las columnas numéricas a continuación, sólo envolver la segunda línea de la función en una sentencia if, como esto: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt
0

En caso de que alguien llegue aquí a través de Google buscando lo contrario (es decir, cómo reemplazar todos los NA en un data.frame con 0), la respuesta es

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

O

Usando dplyr / tidyverse

library(dplyr)
mtcars %>% replace(is.na(.), 0)
stevec
fuente