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.

136voto

mnel Points 48160

Option 1

Utilisez le fait qu'un data.frame est une liste de colonnes, alors utilisez do.call pour recréer un data.frame .

do.call(data.frame,lapply(DT, function(x) replace(x, is.infinite(x),NA)))

Option 2 -- data.table

Vous pourriez utiliser data.table y set . Cela permet d'éviter certaines copies internes.

DT <- data.table(dat)
invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA)))

Ou en utilisant les numéros de colonne (éventuellement plus rapide s'il y a beaucoup de colonnes) :

for (j in 1:ncol(DT)) set(DT, which(is.infinite(DT[[j]])), j, NA)

Horaires

# some `big(ish)` data
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))
# create data.table
library(data.table)
DT <- data.table(dat)

# replace (@mnel)
system.time(na_dat <- do.call(data.frame,lapply(dat, function(x) replace(x, is.infinite(x),NA))))
## user  system elapsed 
#  0.52    0.01    0.53 

# is.na (@dwin)
system.time(is.na(dat) <- sapply(dat, is.infinite))
# user  system elapsed 
# 32.96    0.07   33.12 

# modified is.na
system.time(is.na(dat) <- do.call(cbind,lapply(dat, is.infinite)))
#  user  system elapsed 
# 1.22    0.38    1.60 

# data.table (@mnel)
system.time(invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA))))
# user  system elapsed 
# 0.29    0.02    0.31 

data.table est le plus rapide. Utilisation de sapply ralentit sensiblement les choses.

64voto

BondedDust Points 105234

Utilisez sapply y is.na<-

> dat <- data.frame(a=c(1, Inf), b=c(Inf, 3), d=c("a","b"))
> is.na(dat) <- sapply(dat, is.infinite)
> dat
   a  b d
1  1 NA a
2 NA  3 b

Ou vous pouvez utiliser (en donnant crédit à @mnel, dont c'est l'édition),

> is.na(dat) <- do.call(cbind,lapply(dat, is.infinite))

qui est nettement plus rapide.

29voto

Feng Mai Points 1236

Voici une solution dplyr/tidyverse qui utilise la fonction Fonction na_if() :

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

Notez que cela ne fait que remplacer l'infini positif par NA. Il faut répéter l'opération si les valeurs négatives de l'infini doivent également être remplacées.

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

19voto

Richard Scriven Points 15577

[<- con mapply est un peu plus rapide que sapply .

> dat[mapply(is.infinite, dat)] <- NA

Avec les données de mnel, le timing est

> system.time(dat[mapply(is.infinite, dat)] <- NA)
#   user  system elapsed 
# 15.281   0.000  13.750

8voto

davsjob Points 817

Il existe une solution très simple à ce problème dans le paquet hablar :

library(hablar)

dat %>% rationalize()

qui renvoient un cadre de données avec tous les Inf sont convertis en NA.

Les délais sont comparés à ceux de certaines solutions ci-dessus. Code : library(hablar) library(data.table)

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))
DT <- data.table(dat)

system.time(dat[mapply(is.infinite, dat)] <- NA)
system.time(dat[dat==Inf] <- NA)
system.time(invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA))))
system.time(rationalize(dat))

Résultat :

> system.time(dat[mapply(is.infinite, dat)] <- NA)
   user  system elapsed 
  0.125   0.039   0.164 
> system.time(dat[dat==Inf] <- NA)
   user  system elapsed 
  0.095   0.010   0.108 
> system.time(invisible(lapply(names(DT),function(.name) set(DT, which(is.infinite(DT[[.name]])), j = .name,value =NA))))
   user  system elapsed 
  0.065   0.002   0.067 
> system.time(rationalize(dat))
   user  system elapsed 
  0.058   0.014   0.072 
> 

Il semble que data.table soit plus rapide que hablar. Mais sa syntaxe est plus longue.

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