developer tip

R 데이터 프레임에서`Inf` 값 정리

copycodes 2020. 8. 28. 07:35
반응형

R 데이터 프레임에서`Inf` 값 정리


R Inf에는 데이터 프레임을 변환 할 때 일부 을 생성하는 작업이 있습니다.

이러한 Inf가치를 NA가치 로 바꾸고 싶습니다 . 내가 가진 코드는 대용량 데이터의 경우 느립니다. 더 빠른 방법이 있습니까?

다음 데이터 프레임이 있다고 가정합니다.

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

다음은 단일 경우에서 작동합니다.

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

그래서 다음 루프로 일반화했습니다.

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

그러나 나는 이것이 실제로 R의 힘을 사용하고 있다고 생각하지 않습니다.


옵션 1

a data.frame가 열 목록 이라는 사실을 사용한 다음을 사용 do.call하여 data.frame.

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

옵션 2- data.table

당신은 사용할 수 data.tableset. 이것은 내부 복사를 방지합니다.

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

또는 열 번호 사용 (열이 많은 경우 더 빠름) :

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

타이밍

# 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가장 빠릅니다. 사용하면 sapply눈에 띄게 속도가 느려집니다.


사용 sapplyis.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

또는 사용할 수 있습니다 (편집 인 @mnel에 크레딧 제공),

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

훨씬 빠릅니다.


[<-과는 mapply조금 빠르게보다 sapply.

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

mnel의 데이터를 사용하면 타이밍이

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

다음은 na_if () 함수를 사용하는 dplyr / tidyverse 솔루션입니다 .

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

이것은 양의 무한대를 NA로만 대체합니다. 음의 무한대 값도 교체해야하는 경우 반복해야합니다.

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

hablar 패키지에는이 문제에 대한 매우 간단한 해결책이 있습니다.

library(hablar)

dat %>% rationalize()

모든 Inf가있는 데이터 프레임을 반환하는 것은 NA로 변환됩니다.

위의 일부 솔루션과 비교 한 타이밍입니다. 코드 : 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))

결과:

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

data.table이 hablar보다 빠릅니다. 그러나 더 긴 구문이 있습니다.


또 다른 해결책 :

    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

Here is another base R solution with rapply that slightly outperforms data.table's set in @mnel's benchmark setup.

dat <- data.frame(a = c(1, Inf), b = c(Inf, 3), d = c("a", "b"))
rapply(dat, f = function(x) replace(x, is.infinite(x), NA), classes = "numeric", how = "replace")
#>    a  b d
#> 1  1 NA a
#> 2 NA  3 b

Benchmarks

library(data.table) #v1.12.2
getDTthreads()
#> [1] 4

## rapply approach
replace_inf_rapply <- function(dat) {
  rapply(dat, function(x) replace(x, is.infinite(x), NA), classes = "numeric", how = "replace")
}

## data.table approach
replace_inf_dt <- function(dat) {
  setDT(dat)
  for (j in 1:ncol(dat)) set(dat, which(is.infinite(dat[[j]])), j, NA)
  dat
}

## direct subsetting
replace_inf_index <- function(dat) {
  dat[dat == Inf] <- NA
  dat
}

## benchmarks several data.frame sizes
bnch <- bench::press(
    df_nrows = c(100, 1E4, 1E6),
    {
      dat <- data.frame(a = rep(c(1,Inf), df_nrows), b = rep(c(Inf,2), df_nrows), 
          c = rep(c('a','b'), df_nrows),d = rep(c(1,Inf), df_nrows),  
          e = rep(c(Inf,2), df_nrows))
      bench::mark(
          data.table = replace_inf_dt(dat),
          rapply = replace_inf_rapply(dat),
          index = replace_inf_index(dat)
      )
    }  
)
bnch
#> # A tibble: 9 x 7
#>   expression df_nrows      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>    <dbl> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 data.table      100   74.6µs   99.9µs   9922.    609.91KB    15.3 
#> 2 rapply          100   18.4µs     21µs  45179.      6.66KB    13.6 
#> 3 index           100  112.5µs    137µs   6997.    320.59KB    11.0 
#> 4 data.table    10000  305.2µs  421.4µs   2309.      1.01MB    80.3 
#> 5 rapply        10000  202.3µs  222.7µs   4384.    625.41KB   102.  
#> 6 index         10000  917.4µs  982.6µs    968.      1.64MB    41.7 
#> 7 data.table  1000000   24.6ms   29.2ms     29.7     99.2MB    29.7 
#> 8 rapply      1000000   14.7ms   20.5ms     48.4    61.04MB    32.9 
#> 9 index       1000000    116ms  151.7ms      6.46   152.6MB     9.69


You may also use the handy replace_na function: https://tidyr.tidyverse.org/reference/replace_na.html

참고URL : https://stackoverflow.com/questions/12188509/cleaning-inf-values-from-an-r-dataframe

반응형