Remplacez toutes les valeurs 0 par NA

145

J'ai un dataframe avec quelques colonnes numériques. Certaines lignes ont une valeur 0 qui doit être considérée comme nulle dans l'analyse statistique. Quel est le moyen le plus rapide de remplacer toute la valeur 0 par NULL dans R?

Vu
la source
17
Je ne pense pas que vous voulez / pouvez remplacer par des valeurs NULL, mais NA sert cet objectif dans le jargon R.
Chase le

Réponses:

244

Remplacement de tous les zéros par NA:

df[df == 0] <- NA



Explication

1. Ce n'est pas NULLce que vous devriez vouloir remplacer par des zéros. Comme il est dit dans ?'NULL',

NULL représente l'objet nul dans R

ce qui est unique et, je suppose, peut être considéré comme l'objet le moins informatif et le plus vide. 1 Il n'est alors pas si surprenant que

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

Autrement dit, R ne réserve aucun espace pour cet objet nul. 2 Pendant ce temps, en regardant, ?'NA'nous voyons que

NA est une constante logique de longueur 1 qui contient un indicateur de valeur manquante. NA peut être contraint à n'importe quel autre type de vecteur sauf brut.

Surtout, NAest de longueur 1 pour que R lui réserve de l'espace. Par exemple,

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

De plus, la structure de la trame de données exige que toutes les colonnes aient le même nombre d’éléments afin qu’il n’y ait pas de «trous» (c. NULL valeurs).

Vous pouvez maintenant remplacer les zéros par NULLdans un bloc de données dans le sens de supprimer complètement toutes les lignes contenant au moins un zéro. Lors de l' utilisation, par exemple var, covou cor, qui est en fait équivalent à la première substitution , avec des zéros NAet le réglage de la valeur de useque"complete.obs" . Cependant, cela n'est généralement pas satisfaisant car cela entraîne une perte d'informations supplémentaire.

2. Au lieu d'exécuter une sorte de boucle, dans la solution, j'utilise la df == 0vectorisation. df == 0renvoie (essayez-le) une matrice de même taille que df, avec les entrées TRUEet FALSE. De plus, nous sommes également autorisés à passer cette matrice au sous-ensemble [...](voir ?'['). Enfin, si le résultat de df[df == 0]est parfaitement intuitif, il peut sembler étrange que cela df[df == 0] <- NAdonne l'effet souhaité. L'opérateur d'affectation <-n'est en effet pas toujours aussi intelligent et ne fonctionne pas de cette manière avec certains autres objets, mais il le fait avec des blocs de données; voir ?'<-'.


1 L'ensemble vide dans la théorie des ensembles se sent en quelque sorte lié.
2 Autre similitude avec la théorie des ensembles: l'ensemble vide est un sous-ensemble de chaque ensemble, mais nous ne lui réservons aucun espace.

Julius Vainora
la source
3
Quelle serait la syntaxe équivalente pour un objet data.table?
itpetersen
6
Je vois que vous avez obtenu beaucoup de votes, mais je ne pense pas que cela couvre de manière appropriée les cas extrêmes des colonnes non numériques avec des valeurs de "0" qui n'ont pas été demandées pour être définies sur <NA>.
IRTFM
33

Laissez-moi supposer que votre data.frame est un mélange de différents types de données et que toutes les colonnes n'ont pas besoin d'être modifiées.

pour modifier uniquement les colonnes 12 à 18 (du total 21), il suffit de faire ceci

df[, 12:18][df[, 12:18] == 0] <- NA
userJT
la source
Cela fonctionne pour moi, alors que la réponse acceptée ne fonctionne pas
Patrick Coulombe
23

Une manière alternative sans le [<- fonction:

Un exemple de cadre de données dat(copié sans vergogne à partir de la réponse de @ Chase):

dat

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

Les zéros peuvent être remplacés NApar la is.na<-fonction:

is.na(dat) <- !dat


dat

   x  y
1 NA  2
2  1  2
3  1  1
4  2  1
5 NA NA
Sven Hohenstein
la source
22

dplyr::na_if() est une option:

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
la source
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
Chasse
la source
12

Parce que quelqu'un a demandé la version Data.Table de ceci, et parce que la solution data.frame donnée ne fonctionne pas avec data.table, je propose la solution ci-dessous.

En gros, utilisez l' :=opérateur ->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
la source
2
Ou for (j in names(DT)); set(DT,which(DT[[j]] == 0),j,NA). Voir ici pour une discussion plus détaillée sur l'utilisation de data.table pour rechercher et remplacer des valeurs.
JWilliman
4

Vous pouvez remplacer 0par NAuniquement dans les champs numériques (c'est-à-dire en excluant des éléments tels que les facteurs), mais cela fonctionne colonne par colonne:

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

Avec une fonction, vous pouvez l'appliquer à l'ensemble de votre bloc de données:

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

Bien que vous puissiez remplacer le 1:5par le nombre de colonnes de votre bloc de données ou par 1:ncol(df).

Alium Britt
la source
Je ne suis pas sûr que ce soit la bonne solution. Qu'en est-il des colonnes 6 et plus. Ils seront coupés.
userJT
C'est pourquoi j'ai suggéré de remplacer 1:5par 1:ncol(df)à la fin. Je ne voulais pas rendre l'équation trop complexe ou difficile à lire.
Alium Britt
mais que se passe-t-il si dans les colonnes 6 et 7 - le type de données est char et aucun remplacement ne doit être effectué. Dans mon problème, je n'ai besoin de remplacement que dans les colonnes 12 à 15 mais l'ensemble du df a 21 colonnes (beaucoup ne doivent pas être touchées du tout).
userJT
Pour votre cadre de données que vous pouvez simplement changer 1:5les numéros de colonne que vous voulez modifiés, comme 12:15, mais si vous vouliez confirmer qu'il n'affectera les colonnes numériques puis juste envelopper la deuxième ligne de la fonction dans une instruction if, comme ceci: if (is.numeric(col)) { col[col == -1 & is.numeric(col)] <- NA }.
Alium Britt
0

Dans le cas où quelqu'un arrive ici via google à la recherche du contraire (c'est-à-dire comment remplacer tous les NA d'un data.frame par 0), la réponse est

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

OU

Utilisation de dplyr / tidyverse

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