54 votes

Syntaxe correcte pour mutate_if

Je voudrais remplacer les valeurs NA par des zéros via mutate_if dans dplyr. La syntaxe ci-dessous :

set.seed(1)
mtcars[sample(1:dim(mtcars)[1], 5),
       sample(1:dim(mtcars)[2], 5)] <-  NA

require(dplyr)

mtcars %>% 
    mutate_if(is.na,0)

mtcars %>% 
    mutate_if(is.na, funs(. = 0))

Renvoie une erreur :

Erreur dans vapply(tbl, p, logical(1), ...) : les valeurs doivent être de longueur 1, mais le résultat de FUN(X[[1]]) est de longueur 32

Quelle est la syntaxe correcte pour cette opération ?

5 votes

Pour cette tâche particulière, vous pourriez également envisager le plus simple tidyr::replace_na plutôt que les approches plus génériques de mutate_if

52voto

Hong Ooi Points 17761

Le "if" dans mutate_if se réfère au choix des colonnes, pas des lignes. Par exemple mutate_if(data, is.numeric, ...) signifie effectuer une transformation sur toutes les colonnes numériques de votre jeu de données.

Si vous voulez remplacer tous les NA par des zéros dans les colonnes numériques :

data %>% mutate_if(is.numeric, funs(ifelse(is.na(.), 0, .)))

5 votes

Fonctionnant bien, on pourrait utiliser if_else à la place pour rester dans le tidyverse et bénéficier de la vérification supplémentaire de la cohérence des types TRUE, FALSE

0 votes

Si vous voulez vérifier si c'est NA ou égal à "NA" dans le ifelse, comment pouvez-vous résoudre cela (ajouter une autre condition)

50voto

Yifu Yan Points 1375

J'ai appris ce tour du tutoriel purrr, et cela fonctionne aussi dans dplyr. Il existe deux façons de résoudre ce problème :
Tout d'abord, définissez des fonctions personnalisées en dehors du pipe, et utilisez-les dans mutate_if():

any_column_NA <- function(x){
    any(is.na(x))
}
replace_NA_0 <- function(x){
    if_else(is.na(x),0,x)
}
mtcars %>% mutate_if(any_column_NA,replace_NA_0)

Deuxièmement, utilisez la combinaison de ~, . ou .x. ( .x peut être remplacé par ., mais pas par tout autre caractère ou symbole):

mtcars %>% mutate_if(~ any(is.na(.x)),~ if_else(is.na(.x),0,.x))
#Cela fonctionne aussi
mtcars %>% mutate_if(~ any(is.na(.)),~ if_else(is.na(.),0,.))

Dans votre cas, vous pouvez également utiliser mutate_all():

mtcars %>% mutate_all(~ if_else(is.na(.x),0,.x))

En utilisant ~, nous pouvons définir une fonction anonyme, tandis que .x ou . représente la variable. Dans le cas de mutate_if(), . ou .x est chaque colonne.

0 votes

Le tutoriel Purrr a été déplacé vers rstudio.com/resources/rstudioconf-2017/…

25voto

Nettle Points 995
mtcars %>% mutate_if(is.numeric, replace_na, 0)

ou syntaxe plus récente

mtcars %>% mutate(across(where(is.numeric),
                         replace_na, 0))

0 votes

La simplicité est importante. Si une simple ligne de code peut faire la même chose qu'un code plus complexe et long, je pense qu'il devrait être choisi à la place.

0 votes

Cela devrait figurer dans la page d'aide pour mutate_if. Merci de faciliter ma vie.

4voto

akrun Points 148302

Nous pouvons utiliser set de data.table

library(data.table)
setDT(mtcars)
for(j in seq_along(mtcars)){
  set(mtcars, i= which(is.na(mtcars[[j]])), j = j, value = 0)
 }

0 votes

Comment cela pourrait-il être modifié pour ne fonctionner que sur les variables numériques s'il vous plaît?

1 votes

@RickPack. Vous pourriez changer le for(j in seq_along(mtcars)) en nm1 <- names(mtcars)[mtcars[, unlist(lapply(.SD, is.numeric))]; for(j in nm1)

3voto

Ashish Singhal Points 18

Je lutte toujours avec la fonction replace_na de dplyr

  remplacer(is.na(.),0)

cela fonctionne pour moi pour ce que vous essayez de faire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X