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


101

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의 힘을 사용하고 있다고 생각하지 않습니다.

답변:


119

옵션 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눈에 띄게 속도가 느려집니다.


1
@mnel 타이밍 및 수정에 대한 훌륭한 작업. 계정간에 담당자를 이전하는 방법이 있었으면합니다. 나는 나가서 당신의 다른 답변을 찬성 할 것이라고 생각합니다.
IRTFM

do.call (train, lapply (train, function (x) replace (x, is.infinite (x), : 'what'은 문자열 또는 함수 여야합니다.
Hack-R

60

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

훨씬 빠릅니다.


5
"속임수"는에서 is.na<-결과를 lapply받아들이지 않고에서 하나를 받아 들일 것임을 깨닫는 데있었습니다 sapply.
IRTFM

몇 가지 타이밍을 추가했습니다. is.na<-솔루션이 왜 그렇게 느린 지 잘 모르겠습니다 .
mnel

약간의 프로파일 링을 통해 훨씬 더 빠르게 솔루션을 편집했습니다.
mnel

19

[<-과는 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 

11

다음은 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)))

5

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보다 빠릅니다. 그러나 더 긴 구문이 있습니다.


타이밍 제발?
ricardo

약간의 타이밍을 추가 @ricardo
davsjob

1

Feng Mai는 부정적이고 긍정적 인 무한대를 얻기 위해 위의 깔끔한 대답을 가지고 있습니다.

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

이것은 잘 작동하지만, 찬성 주석에서 제안 된 것처럼 한 번에 두 줄을 모두 수행하기 위해 여기에서 abs (.)를 바꾸지 않는 것이 경고의 말씀입니다. 작동하는 것처럼 보이지만 데이터 세트의 모든 음수 값을 양수로 변경합니다! 다음으로 확인할 수 있습니다.

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

한 줄의 경우 다음과 같이 작동합니다.

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

1
잘 잡아! 원본 댓글에 대한이 영향에 대한 댓글을 추가했습니다. 새로운 답변보다 문제를 해결하기에 더 좋은 곳이라고 생각합니다. 또한 귀하의 게시물 중 일부는 어디에서나 댓글을다는 데 필요한 50 개의 평판에 조금 더 가까이 다가 갈 수 있도록 찬성 할만한 가치가있는 게시물을 찾았습니다.
Gregor Thomas

감사! 예, 가능하다면 댓글을 남겼을 것입니다.
Mark E.

0

또 다른 해결책 :

    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

MusTheDataGuy, 왜 내 대답을 편집하고 자신의 솔루션을 추가하지 않습니까? 이미 "다른 답변 추가"버튼이 있습니다!
학생

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.