모든 값이 NA 인 데이터 프레임에서 열 제거


149

나는 데이터 프레임에 문제가 정말 그 문제를 자신을 확인할 수 없습니다 : dataframe은 임의의가 열 등의 속성을 하고 각 행은 하나 개를 나타냅니다 데이터 세트를 .

질문 :
어떻게하는 어디에서 열을 제거 ALL 행 값이 NA는 ?

답변:


155

이 시도:

df <- df[,colSums(is.na(df))<nrow(df)]

3
이것은 큰 객체의 메모리에 문제가있는 오래된 객체의 크기로 객체를 만듭니다. 크기를 줄이는 기능을 사용하는 것이 좋습니다. Filter를 사용하거나 data.table을 사용하면 다음과 같은 대답이 메모리 사용에 도움이됩니다.
mtelesha

3
숫자가 아닌 열에는 작동하지 않는 것 같습니다.
verbamour

열이 중복되면 열 이름이 변경됩니다
Peter.k

97

지금까지 제공된 두 가지 접근 방식은 (다른 메모리 문제 중) 생성 is.na(df)하는 것과 같은 대용량 데이터 세트에서는 실패 합니다.df .

더 많은 메모리와 시간 효율적인 두 가지 접근법이 있습니다.

사용하는 접근법 Filter

Filter(function(x)!all(is.na(x)), df)

data.table을 사용하는 접근법 (일반적인 시간과 메모리 효율성을 위해)

library(data.table)
DT <- as.data.table(df)
DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]

큰 데이터를 사용하는 예 (30 열, 1e6 행)

big_data <- replicate(10, data.frame(rep(NA, 1e6), sample(c(1:8,NA),1e6,T), sample(250,1e6,T)),simplify=F)
bd <- do.call(data.frame,big_data)
names(bd) <- paste0('X',seq_len(30))
DT <- as.data.table(bd)

system.time({df1 <- bd[,colSums(is.na(bd) < nrow(bd))]})
# error -- can't allocate vector of size ...
system.time({df2 <- bd[, !apply(is.na(bd), 2, all)]})
# error -- can't allocate vector of size ...
system.time({df3 <- Filter(function(x)!all(is.na(x)), bd)})
## user  system elapsed 
## 0.26    0.03    0.29 
system.time({DT1 <- DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]})
## user  system elapsed 
## 0.14    0.03    0.18 

6
아주 좋아요 data.frame그래도 같은 작업을 수행 할 수 있습니다. 여기 정말로 필요한 것은 없습니다 data.table. 열쇠는 lapply이며, 전체 객체의 복사를 피합니다 is.na(df). 지적 +10
Matt Dowle

1
data.frame으로 어떻게 할 것입니까? @ matt-dowle
s_a

8
@s_a, bd1 <- bd[, unlist(lapply(bd, function(x), !all(is.na(x))))]
mnel

6
@mnel 난 당신이 ,후 후 제거해야한다고 생각 function(x)-예 btw에 대한 감사
Thieme Hennis

1
: = 또는 set ()으로 더 빨리 할 수 ​​있습니까?
skan

49

dplyr지금이 select_if여기에 도움이 될 수있는 동사를 :

library(dplyr)
temp <- data.frame(x = 1:5, y = c(1,2,NA,4, 5), z = rep(NA, 5))
not_all_na <- function(x) any(!is.na(x))
not_any_na <- function(x) all(!is.na(x))

> temp
  x  y  z
1 1  1 NA
2 2  2 NA
3 3 NA NA
4 4  4 NA
5 5  5 NA

> temp %>% select_if(not_all_na)
  x  y
1 1  1
2 2  2
3 3 NA
4 4  4
5 5  5

> temp %>% select_if(not_any_na)
  x
1 1
2 2
3 3
4 4
5 5

dplyr해결책을 찾아 여기에 왔습니다 . 실망하지 않았습니다. 감사!
Andrew Brēza

나는 이것이 또한 대부분의 값이없는 변수를 삭제하는 문제가 있음을 발견했다
MBorg

15

다른 방법은 apply()기능 을 사용하는 것입니다.

data.frame이있는 경우

df <- data.frame (var1 = c(1:7,NA),
                  var2 = c(1,2,1,3,4,NA,NA,9),
                  var3 = c(NA)
                  )

그러면 apply()어떤 열이 조건을 충족하는지 확인할 수 있으므로 apply접근 방식 만으로 Musa의 답변에서와 동일한 하위 설정을 수행 할 수 있습니다 .

> !apply (is.na(df), 2, all)
 var1  var2  var3 
 TRUE  TRUE FALSE 

> df[, !apply(is.na(df), 2, all)]
  var1 var2
1    1    1
2    2    2
3    3    1
4    4    3
5    5    4
6    6   NA
7    7   NA
8   NA    9

3
colSum () 솔루션이 더 많은 작업을 수행하는 것처럼 보였기 때문에 이것이 더 빠를 것으로 예상했습니다. 그러나 내 테스트 세트 (이전에는 1377 개의 변수에 비해 214 개의 1614 개의 변수)가 정확히 3 배 더 걸립니다. (하지만 흥미로운 접근법은 +1)
대런 쿡

10

게임에 늦었지만 janitor패키지 를 사용할 수도 있습니다 . 이 함수는 모두 NA 인 열을 제거하고 모두 NA 인 행을 제거하도록 변경 될 수 있습니다.

df <- janitor::remove_empty(df, which = "cols")



4

허용되는 답변은 숫자가 아닌 열에는 적용되지 않습니다. 에서 이 대답 , 다음은 서로 다른 데이터 유형을 포함하는 열이 작동

Filter(function(x) !all(is.na(x)), df)

4 년 전에이 스레드에서 다른 사람이 이미 동일한 답변을 게시했습니다. 아래 mnel의 답변을 참조하십시오.
André.B

2

purrr패키지 와 함께 다른 옵션 :

library(dplyr)

df <- data.frame(a = NA,
                 b = seq(1:5), 
                 c = c(rep(1, 4), NA))

df %>% purrr::discard(~all(is.na(.)))
df %>% purrr::keep(~!all(is.na(.)))

1

이것이 도움이되기를 바랍니다. 단일 명령으로 만들 수는 있지만 두 명령으로 나누면 더 읽기 쉽습니다. 나는 다음과 같은 명령으로 기능하고 번개를 빨리 일했습니다.

naColsRemoval = function (DataTable) { na.cols = DataTable [ , .( which ( apply ( is.na ( .SD ) , 2 , all ) ) )] DataTable [ , unlist (na.cols) := NULL , with = F] }

.SD는 원하는 경우 확인을 테이블의 일부로 제한 할 수 있지만 전체 테이블을 다음과 같이 사용합니다.


1

편리한 base R옵션은 다음과 colMeans()같습니다.

df[, colMeans(is.na(df)) != 1]

0

관리인 패키지를 사용할 수 있습니다 remove_empty

library(janitor)

df %>%
  remove_empty(c("rows", "cols")) #select either row or cols or both

또한, 또 다른 dplyr 접근법

 library(dplyr) 
 df %>% select_if(~all(!is.na(.)))

또는

df %>% select_if(colSums(!is.na(.)) == nrow(df))

이것은 특정 개수의 결 측값이있는 열만 제외 / 유지하려는 경우에도 유용합니다. 예 :

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