125 votes

Nettoyage des valeurs `Inf` d'un dataframe R

Dans R, j'ai une opération qui crée des Inf lorsque je transforme un cadre de données.

Je voudrais transformer ces Inf en valeurs NA valeurs. Le code que j'ai est lent pour les grandes données, existe-t-il un moyen plus rapide de le faire ?

Disons que j'ai le cadre de données suivant :

dat <- data.frame(a=c(1, Inf), b=c(Inf, 3), d=c("a","b"))

Ce qui suit fonctionne dans un seul cas :

 dat[,1][is.infinite(dat[,1])] = NA

Je l'ai donc généralisé avec la boucle suivante

cf_DFinf2NA <- function(x)
{
    for (i in 1:ncol(x)){
          x[,i][is.infinite(x[,i])] = NA
    }
    return(x)
}

Mais je ne pense pas que ce soit vraiment utiliser la puissance de R.

3voto

Mark E. Points 130

Feng Mai a une réponse tidyverse ci-dessus pour obtenir les infinis négatifs et positifs :

dat %>% mutate_if(is.numeric, list(~na_if(., Inf))) %>% 
  mutate_if(is.numeric, list(~na_if(., -Inf)))

Cela fonctionne bien, mais un mot d'avertissement est de ne pas échanger dans abs(.) ici pour faire les deux lignes à la fois comme il est proposé dans un commentaire upvoted. Cela aura l'air de fonctionner, mais changera toutes les valeurs négatives de l'ensemble de données en valeurs positives ! Vous pouvez confirmer avec ceci :

data(iris)
#The last line here is bad - it converts all negative values to positive
iris %>% 
  mutate_if(is.numeric, ~scale(.)) %>%
  mutate(infinities = Sepal.Length / 0) %>%
  mutate_if(is.numeric, list(~na_if(abs(.), Inf)))

Pour une ligne, ça marche :

  mutate_if(is.numeric, ~ifelse(abs(.) == Inf,NA,.))

2voto

Sagar Points 71

A l'intérieur d'une chaîne de tuyaux dplyr, vous pouvez faire cela.

%>% mutate_all(.,.funs = function(x){ifelse(is.infinite(x),NA,x)}) %>%

Je le trouve simple, élégant et rapide.

2voto

ToWii Points 441

Il y a déjà beaucoup de réponses, mais je voudrais ajouter que pour moi cette tidyverse Cette solution a toujours bien fonctionné :

%>% mutate_all(function(x) ifelse(is.nan(x) | is.infinite(x), NA, x)) %>%

0voto

Student Points 23

Une autre solution :

    dat <- data.frame(a = rep(c(1,Inf), 1e6), b = rep(c(Inf,2), 1e6), 
                      c = rep(c('a','b'),1e6),d = rep(c(1,Inf), 1e6),  
                      e = rep(c(Inf,2), 1e6))
    system.time(dat[dat==Inf] <- NA)

#   user  system elapsed
#  0.316   0.024   0.340

0voto

Aussi, si quelqu'un a besoin des coordonnées de l'infanterie, je peux le faire :

library(rlist)
list.clean(apply(df, 2, function(x){which(is.infinite(x))}), function(x) length(x) == 0L, TRUE)

Résultat :

$colname1
[1] row1 row2 ...
$colname2
[2] row1 row2 ... 

Avec ces informations, vous pouvez remplacer les valeurs Inf à des endroits particuliers par la moyenne, la médiane ou tout autre opérateur de votre choix.

Par exemple (pour l'élément 01) :

repInf = list.clean(apply(df, 2, function(x){which(is.infinite(x))}), function(x) length(x) == 0L, TRUE)
df[repInf[[1]], names(repInf)[[1]]] = median or mean(is.finite(df[ ,names(repInf)[[1]]]), na.rm = TRUE)

En boucle :

for (nonInf in 1:length(repInf)) {
df[repInf[[nonInf]], names(repInf)[[nonInf]]] = mean(is.finite(df[ , names(repInf)[[nonInf]]]))
}

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