programing

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

css3 2023. 7. 9. 12:37

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

일부 열에 NA 값이 포함된 데이터 프레임이 있습니다.

모든 행에 NA 값이 포함된 열을 제거하려면 어떻게 해야 합니까?

사용해 보십시오.

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

지금까지 제공된 두 가지 접근 방식은 (다른 메모리 문제 중에서도) 대용량 데이터 세트에서 실패합니다.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 

갱신하다

이제 사용할 수 있습니다.select와 함께where선발 도우미 select_if는 대체되었지만 dplyr 1.0.2에서 여전히 작동합니다. (이것을 주목해 준 @mcstrother 덕분입니다.)

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(where(not_all_na))
  x  y
1 1  1
2 2  2
3 3 NA
4 4  4
5 5  5

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

오래된 대답

dplyr이제는select_if여기서 도움이 될 수 있는 동사:

> 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

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

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

다른 방법은 다음을 사용하는 것입니다.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접근.

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

다음을 포함하는 다른 옵션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(.)))
df[sapply(df, function(x) all(is.na(x)))] <- NULL

오래된 질문이지만 더 간단한 data.table 솔루션으로 @mnel의 멋진 답변을 업데이트할 수 있을 것 같습니다.

DT[, .SD, .SDcols = \(x) !all(is.na(x))]

(새 제품을 사용하고 있습니다.\(x)R>=4.1에서 람다 함수 구문을 사용할 수 있지만, 실제로 중요한 것은 논리적 부분 집합을 통과시키는 것입니다..SDcols.

속도는 동등합니다.

microbenchmark::microbenchmark(
  which_unlist = DT[, which(unlist(lapply(DT, \(x) !all(is.na(x))))), with=FALSE],
  sdcols       = DT[, .SD, .SDcols = \(x) !all(is.na(x))],
  times = 2
)
#> Unit: milliseconds
#>          expr      min       lq     mean   median       uq      max neval cld
#>  which_unlist 51.32227 51.32227 56.78501 56.78501 62.24776 62.24776     2   a
#>        sdcols 43.14361 43.14361 49.33491 49.33491 55.52621 55.52621     2   a

Janitor 패키지를 사용할 수 있습니다.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(.)))

OR

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

또한 특정 개수의 결측값이 있는 열만 제외/보관하려는 경우에도 유용합니다.

 df %>% select_if(colSums(!is.na(.))>500)

핸디base R선택사항은 다음과 같습니다.colMeans():

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

이것도 도움이 되길 바랍니다.하나의 명령어로 만들 수도 있지만, 두 개의 명령어로 나누어서 읽는 것이 더 쉽다는 것을 알게 되었습니다.저는 다음과 같은 지시로 함수를 만들어 번개처럼 빠르게 작업했습니다.

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

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

janitor::remove_constant() 

이것은 매우 잘 합니다.

이전 답변을 적용하는 데 어려움을 겪은 경험을 바탕으로, 여기서 질문이 무엇인지를 달성하기 위해서는 다음과 같은 접근 방식을 수정해야 한다는 것을 알게 되었습니다.

모든 행의 값이 NA인 열을 제거하는 방법은 무엇입니까?

먼저 중복 열이 없는 경우에만 내 솔루션이 작동합니다(이 문제는 여기서 처리됩니다(스택 오버플로).

둘째, 그것은 사용합니다.dplyr.

대신에

df <- df %>% select_if(~all(!is.na(.)))

저는 효과가 있는 것입니다.

df <- df %>% select_if(~!all(is.na(.)))

요점은 "아니요" 기호 "!"가 범용 정량기의 외부에 있어야 한다는 것입니다.즉, 그select_if연산자가 열에 작용합니다.이 경우 기준을 충족하지 않는 항목만 선택합니다.

모든 요소는 "NA"와 같습니다.

library(dplyr)

# create a sample data frame
df <- data.frame(x = c(1, 2, NA, 4),
                 y = c(NA, NA, NA, NA),
                 z = c(6, 7, NA, 9))

# remove columns with all NAs
df <- df %>%
  select_if(~!all(is.na(.)))

언급URL : https://stackoverflow.com/questions/2643939/remove-columns-from-dataframe-where-all-values-are-na