Substitua todos os 0 valores para NA

144

Eu tenho um quadro de dados com algumas colunas numéricas. Alguma linha tem um valor 0 que deve ser considerado nulo na análise estatística. Qual é a maneira mais rápida de substituir todo o valor 0 para NULL em R?

Visto
fonte
17
Eu não acho que você queira / possa substituir por valores NULL, mas NA serve a esse propósito na linguagem R.
Perseguição

Respostas:

243

Substituindo todos os zeros para NA:

df[df == 0] <- NA



Explicação

1. Não é com o NULLque você deseja substituir os zeros. Como diz em ?'NULL',

NULL representa o objeto nulo em R

que é único e, eu acho, pode ser visto como o objeto menos informativo e vazio. 1 Então não é tão surpreendente que

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

Ou seja, R não reserva nenhum espaço para esse objeto nulo. 2 Enquanto isso, ?'NA'observamos que

NA é uma constante lógica de comprimento 1 que contém um indicador de valor ausente. O NA pode ser coagido a qualquer outro tipo de vetor, exceto bruto.

Importante, NAé de comprimento 1, de modo que R reserva algum espaço para ele. Por exemplo,

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

Além disso, a estrutura do quadro de dados exige que todas as colunas tenham o mesmo número de elementos para que não haja "buracos" ( NULLvalores).

Agora você pode substituir os zeros NULLem um quadro de dados no sentido de remover completamente todas as linhas que contêm pelo menos um zero. Quando se utiliza, por exemplo, var, cov, ou cor, que é, na verdade, equivalente a primeira substituição com zeros NAe definindo o valor de usecomo "complete.obs". Normalmente, porém, isso é insatisfatório, pois leva à perda de informações extras.

2. Em vez de executar algum tipo de loop, na solução eu uso a df == 0vetorização. df == 0retorna (tente) uma matriz do mesmo tamanho que df, com as entradas TRUEe FALSE. Além disso, também podemos passar essa matriz para o subconjunto [...](veja ?'['). Por fim, embora o resultado de df[df == 0]seja perfeitamente intuitivo, pode parecer estranho que df[df == 0] <- NAproduz o efeito desejado. O operador de atribuição <-nem sempre é tão inteligente e não funciona dessa maneira com outros objetos, mas com quadros de dados; veja ?'<-'.


1 O conjunto vazio na teoria dos conjuntos parece de alguma forma relacionado.
2 Outra semelhança com a teoria dos conjuntos: o conjunto vazio é um subconjunto de todos os conjuntos, mas não reservamos espaço para ele.

Julius Vainora
fonte
3
Qual seria a sintaxe equivalente para um objeto data.table?
precisa saber é o seguinte
6
Vejo que você obteve muitos votos, mas não acho que isso abranja adequadamente os casos extremos de colunas não numéricas com valores "0" que não foram solicitados para serem definidos como <NA>.
IRTFM
33

Deixe-me supor que seu data.frame é uma mistura de tipos de dados diferentes e nem todas as colunas precisam ser modificadas.

para modificar apenas as colunas 12 a 18 (do total de 21), faça isso

df[, 12:18][df[, 12:18] == 0] <- NA
userJT
fonte
Isso funciona para mim, enquanto a resposta aceita não
Patrick Coulombe
23

Uma maneira alternativa sem a [<-função:

Um exemplo de quadro de dados dat(copiado descaradamente da resposta de @ Chase):

dat

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

Os zeros podem ser substituídos NApor pela is.na<-função:

is.na(dat) <- !dat


dat

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

dplyr::na_if() é uma opção:

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
fonte
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
correr atrás
fonte
12

Como alguém pediu a versão Data.Table disso e porque a solução data.frame fornecida não funciona com data.table, estou fornecendo a solução abaixo.

Basicamente, use o :=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
fonte
2
Or for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Veja aqui uma discussão mais detalhada sobre o uso de data.table para encontrar e substituir valores.
JWilliman
4

Você pode substituir 0com NAapenas em campos numéricos (ou seja, excluindo coisas como fatores), mas funciona em uma base coluna por coluna:

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

Com uma função, você pode aplicar isso a todo o seu quadro de dados:

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

Embora você possa substituir o 1:5com o número de colunas no seu quadro de dados ou com 1:ncol(df).

Alium Britt
fonte
Não tenho certeza se esta é a solução correta. E as colunas 6 e mais. Eles serão cortados.
userJT
É por isso que sugeri substituir 1:5por 1:ncol(df)no final. Não queria tornar a equação excessivamente complexa ou difícil de ler.
Alium Britt
mas e se nas colunas 6 e 7 - o tipo de dados for char e nenhuma substituição for feita. No meu problema, preciso substituir apenas nas colunas 12 a 15, mas o df inteiro possui 21 colunas (muitas não devem ser tocadas).
userJT
Para o seu quadro de dados você pode simplesmente mudar o 1:5que os números das colunas que pretende alterar, como 12:15, mas se você queria confirmar que ela só vai afetar colunas numéricas, em seguida, só embrulhar a segunda linha da função em uma instrução if, como este: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt
0

Caso alguém chegue aqui via google procurando o oposto (ou seja, como substituir todos os NAs em um data.frame por 0), a resposta é

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

OU

Usando dplyr / tidyverse

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