data.frame에서 전부 또는 일부 NA (결 측값)가있는 행 제거


851

이 데이터 프레임에서 다음과 같은 행을 제거하고 싶습니다.

a) 모든 열에을 포함합니다 NA. 아래는 내 예제 데이터 프레임입니다.

             gene hsap mmul mmus rnor cfam
1 ENSG00000208234    0   NA   NA   NA   NA
2 ENSG00000199674    0   2    2    2    2
3 ENSG00000221622    0   NA   NA   NA   NA
4 ENSG00000207604    0   NA   NA   1    2
5 ENSG00000207431    0   NA   NA   NA   NA
6 ENSG00000221312    0   1    2    3    2

기본적으로 다음과 같은 데이터 프레임을 얻고 싶습니다.

             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0   2    2    2    2
6 ENSG00000221312    0   1    2    3    2

b) 일부 열에 만을 포함 NA하므로이 결과를 얻을 수도 있습니다.

             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0   2    2    2    2
4 ENSG00000207604    0   NA   NA   1    2
6 ENSG00000221312    0   1    2    3    2

답변:


1062

또한 확인 complete.cases:

> final[complete.cases(final), ]
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0    2    2    2    2
6 ENSG00000221312    0    1    2    3    2

na.omit를 모두 제거하는 것이 NA좋습니다. complete.cases데이터 프레임의 특정 열만 포함하여 부분 선택을 허용합니다.

> final[complete.cases(final[ , 5:6]),]
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0    2    2    2    2
4 ENSG00000207604    0   NA   NA    1    2
6 ENSG00000221312    0    1    2    3    2

솔루션이 작동하지 않습니다. 를 사용한다고 주장하면 is.na다음과 같은 작업을 수행해야합니다.

> final[rowSums(is.na(final[ , 5:6])) == 0, ]
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0    2    2    2    2
4 ENSG00000207604    0   NA   NA    1    2
6 ENSG00000221312    0    1    2    3    2

사용하는 complete.cases것이 훨씬 더 명확하고 빠릅니다.


8
후행 쉼표의 의미는 무엇입니까 final[complete.cases(final),]?
hertzsprung

6
@hertzsprung 열이 아닌 행을 선택해야합니다. 다른 방법은 무엇입니까?
Joris Meys

4
간단한 부정이 complete.cases있습니까? 버리는 대신 NA로 행을 유지하려면? final[ ! complete.cases(final),]협조하지 않습니다 ...
tumultous_rooster

2
final데이터 프레임은 가변적입니까?
Morse

1
@Prateek는 사실입니다.
Joris Meys

256

시도하십시오 na.omit(your.data.frame). 두 번째 질문은 명확성을 위해 다른 질문으로 게시하십시오.


na.omit은 행을 삭제하지만 행 번호는 유지합니다. 제대로 번호가 매겨 지도록이 문제를 어떻게 해결 하시겠습니까?
Bear

3
@ 행 번호에 신경 쓰지 않는다면 그냥하십시오 rownames(x) <- NULL.
Roman Luštrik

제발 참고 na.omit()포함 된 행 떨어질 NA모든 열에서
빅터 맥스웰

116

tidyr새로운 기능이 있습니다 drop_na:

library(tidyr)
df %>% drop_na()
#              gene hsap mmul mmus rnor cfam
# 2 ENSG00000199674    0    2    2    2    2
# 6 ENSG00000221312    0    1    2    3    2
df %>% drop_na(rnor, cfam)
#              gene hsap mmul mmus rnor cfam
# 2 ENSG00000199674    0    2    2    2    2
# 4 ENSG00000207604    0   NA   NA    1    2
# 6 ENSG00000221312    0    1    2    3    2

3
파이프와 사이에 실제 연결이 없습니다 drop_na. 예를 들어 df %>% drop_na(), df %>% na.omit()drop_na(df)모두 기본적으로 동일합니다.
Ista

4
@Ista 동의하지 않습니다. na.omit생략 된 경우의 색인과 같은 추가 정보를 추가하고 더 중요한 것은 열을 선택할 수 없다는 것 drop_na입니다. 이곳 이 빛납니다.
lukeA 2016 년

3
물론, 요점은 파이프와 관련이없는 것입니다. 당신은 사용할 수 있습니다 na.omit당신이 사용할 수있는 것처럼, 또는 파이프없이 drop_na또는 파이프없이.
Ista

1
사실 파이프와는 전혀 관련이 없습니다. drop_na ()는 다른 함수와 마찬가지로 함수이므로 직접 또는 파이프를 사용하여 호출 할 수 있습니다. 불행히도 drop_na ()는 다른 언급 된 방법과 달리 zoo 또는 xts 객체 유형에서 사용할 수 없습니다. 이것은 일부 사람들에게 문제가 될 수 있습니다.
Dave

맞습니다. 그래서 파이프를 언급하지 않도록 답변을 편집했습니다.
Arthur Yip

91

행에 NA가 포함되어 있는지 확인하는 다음 방법을 선호합니다.

row.has.na <- apply(final, 1, function(x){any(is.na(x))})

행에 NA가 있는지 여부를 나타내는 값을 가진 논리 형 벡터를 반환합니다. 이를 사용하여 삭제해야하는 행 수를 확인할 수 있습니다.

sum(row.has.na)

결국에는 떨어 뜨려

final.filtered <- final[!row.has.na,]

NA의 특정 부분으로 행을 필터링하는 경우 조금 까다로워집니다 (예 : 'final [, 5 : 6]'을 '적용'에 공급할 수 있음). 일반적으로 Joris Meys의 솔루션은 더 우아해 보입니다.


2
이것은 매우 느립니다. 예를 들어 앞에서 언급 한 complete.cases () 솔루션보다 훨씬 느립니다. 적어도 내 경우에는 xts 데이터에 관한 것입니다.
Dave

3
rowSum(!is.na(final))보다 적합한 것 같습니다apply()
sindri_baldur

45

행이 유효하지 않은 것으로 간주되는 방법을 더 잘 제어하려는 경우 다른 옵션은

final <- final[!(is.na(final$rnor)) | !(is.na(rawdata$cfam)),]

위의 내용을 사용하면 다음과 같습니다.

             gene hsap mmul mmus rnor cfam
1 ENSG00000208234    0   NA   NA   NA   2
2 ENSG00000199674    0   2    2    2    2
3 ENSG00000221622    0   NA   NA   2   NA
4 ENSG00000207604    0   NA   NA   1    2
5 ENSG00000207431    0   NA   NA   NA   NA
6 ENSG00000221312    0   1    2    3    2

된다 :

             gene hsap mmul mmus rnor cfam
1 ENSG00000208234    0   NA   NA   NA   2
2 ENSG00000199674    0   2    2    2    2
3 ENSG00000221622    0   NA   NA   2   NA
4 ENSG00000207604    0   NA   NA   1    2
6 ENSG00000221312    0   1    2    3    2

... 5 행만 제거되고 rnorAND 모두에 대해 NA를 포함하는 유일한 행이므로 제거됩니다 cfam. 그런 다음 부울 논리를 특정 요구 사항에 맞게 변경할 수 있습니다.


5
그러나 각 열을 입력하지 않고 많은 열을 확인하려면 final [, 4 : 100] 범위를 사용할 수 있습니까?
Herman Toothrot

40

각 행에 유효한 NA 수를 제어하려면이 기능을 사용해보십시오. 많은 설문 조사 데이터 세트의 경우 너무 많은 빈 질문 응답이 결과를 망칠 수 있습니다. 따라서 특정 임계 값 후에 삭제됩니다. 이 기능을 사용하면 행이 삭제되기 전에 보유 할 수있는 NA 수를 선택할 수 있습니다.

delete.na <- function(DF, n=0) {
  DF[rowSums(is.na(DF)) <= n,]
}

기본적으로 모든 NA가 제거됩니다.

delete.na(final)
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0    2    2    2    2
6 ENSG00000221312    0    1    2    3    2

또는 허용되는 최대 NA 수를 지정하십시오.

delete.na(final, 2)
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0    2    2    2    2
4 ENSG00000207604    0   NA   NA    1    2
6 ENSG00000221312    0    1    2    3    2

39

성능이 우선 순위 인 경우 data.tablena.omit()옵션 param 과 함께 사용하십시오 cols=.

na.omit.data.table 모든 열 또는 선택 열에 대해 내 벤치 마크에서 가장 빠릅니다 (아래 참조) (OP 질문 파트 2).

을 사용하지 않으려면을 data.table사용하십시오 complete.cases().

바닐라 data.frame에서는 또는 complete.cases보다 빠릅니다 . 공지 사항 을 지원하지 않습니다 .na.omit()dplyr::drop_na()na.omit.data.framecols=

벤치 마크 결과

다음은 독립적 인 5 %의 누락 가능성이있는 20 개의 숫자 변수에 대한 백만 개의 관측치에 대한 명목 데이터 세트에서 누락 된 관측치를 모두 제거하거나 누락 된 관측치를 선택 하는 기본 (파란색), dplyr(분홍색) 및 data.table(노란색) 방법과 파트 2에 대한 4 개의 변수 서브 세트

결과는 특정 데이터 집합의 길이, 너비 및 희소성에 따라 달라질 수 있습니다.

y 축의 로그 스케일을 기록하십시오.

여기에 이미지 설명을 입력하십시오

벤치 마크 스크립트

#-------  Adjust these assumptions for your own use case  ------------
row_size   <- 1e6L 
col_size   <- 20    # not including ID column
p_missing  <- 0.05   # likelihood of missing observation (except ID col)
col_subset <- 18:21  # second part of question: filter on select columns

#-------  System info for benchmark  ----------------------------------
R.version # R version 3.4.3 (2017-11-30), platform = x86_64-w64-mingw32
library(data.table); packageVersion('data.table') # 1.10.4.3
library(dplyr);      packageVersion('dplyr')      # 0.7.4
library(tidyr);      packageVersion('tidyr')      # 0.8.0
library(microbenchmark)

#-------  Example dataset using above assumptions  --------------------
fakeData <- function(m, n, p){
  set.seed(123)
  m <-  matrix(runif(m*n), nrow=m, ncol=n)
  m[m<p] <- NA
  return(m)
}
df <- cbind( data.frame(id = paste0('ID',seq(row_size)), 
                        stringsAsFactors = FALSE),
             data.frame(fakeData(row_size, col_size, p_missing) )
             )
dt <- data.table(df)

par(las=3, mfcol=c(1,2), mar=c(22,4,1,1)+0.1)
boxplot(
  microbenchmark(
    df[complete.cases(df), ],
    na.omit(df),
    df %>% drop_na,
    dt[complete.cases(dt), ],
    na.omit(dt)
  ), xlab='', 
  main = 'Performance: Drop any NA observation',
  col=c(rep('lightblue',2),'salmon',rep('beige',2))
)
boxplot(
  microbenchmark(
    df[complete.cases(df[,col_subset]), ],
    #na.omit(df), # col subset not supported in na.omit.data.frame
    df %>% drop_na(col_subset),
    dt[complete.cases(dt[,col_subset,with=FALSE]), ],
    na.omit(dt, cols=col_subset) # see ?na.omit.data.table
  ), xlab='', 
  main = 'Performance: Drop NA obs. in select cols',
  col=c('lightblue','salmon',rep('beige',2))
)

18

dplyr 패키지를 사용하여 다음과 같이 NA를 필터링 할 수 있습니다.

dplyr::filter(df,  !is.na(columnname))

1
보다 느린 10.000 배에 대한이 수행drop_na()
Zimano

17

이것은 하나 이상의 비 NA 값을 가진 행을 반환합니다.

final[rowSums(is.na(final))<length(final),]

이것은 적어도 두 개의 비 NA 값을 가진 행을 리턴합니다.

final[rowSums(is.na(final))<(length(final)-1),]

16

첫 번째 질문으로 모든 NA를 제거하기에 편안한 코드가 있습니다. 더 간단하게 해줄 @Gregor에게 감사합니다.

final[!(rowSums(is.na(final))),]

두 번째 질문의 경우 코드는 이전 솔루션의 대안입니다.

final[as.logical((rowSums(is.na(final))-5)),]

-5는 데이터의 열 수입니다. rowSums는 최대 5를 더하고 빼기 후 0이되기 때문에 모든 NA가있는 행을 제거합니다. 이번에는 as.logical이 필요합니다.


최종적인 [as.logical ((rowSums (is.na (final))-ncol (final))),] 일반 답변
Ferroao

14

이를 위해 서브셋 기능을 사용할 수도 있습니다.

finalData<-subset(data,!(is.na(data["mmul"]) | is.na(data["rnor"])))

이것은 mmul과 rnor 모두에 NA가없는 행만 제공합니다.


9

나는 신디사이저입니다 :). 여기에 답을 하나의 함수로 결합했습니다.

#' keep rows that have a certain number (range) of NAs anywhere/somewhere and delete others
#' @param df a data frame
#' @param col restrict to the columns where you would like to search for NA; eg, 3, c(3), 2:5, "place", c("place","age")
#' \cr default is NULL, search for all columns
#' @param n integer or vector, 0, c(3,5), number/range of NAs allowed.
#' \cr If a number, the exact number of NAs kept
#' \cr Range includes both ends 3<=n<=5
#' \cr Range could be -Inf, Inf
#' @return returns a new df with rows that have NA(s) removed
#' @export
ez.na.keep = function(df, col=NULL, n=0){
    if (!is.null(col)) {
        # R converts a single row/col to a vector if the parameter col has only one col
        # see https://radfordneal.wordpress.com/2008/08/20/design-flaws-in-r-2-%E2%80%94-dropped-dimensions/#comments
        df.temp = df[,col,drop=FALSE]
    } else {
        df.temp = df
    }

    if (length(n)==1){
        if (n==0) {
            # simply call complete.cases which might be faster
            result = df[complete.cases(df.temp),]
        } else {
            # credit: http://stackoverflow.com/a/30461945/2292993
            log <- apply(df.temp, 2, is.na)
            logindex <- apply(log, 1, function(x) sum(x) == n)
            result = df[logindex, ]
        }
    }

    if (length(n)==2){
        min = n[1]; max = n[2]
        log <- apply(df.temp, 2, is.na)
        logindex <- apply(log, 1, function(x) {sum(x) >= min && sum(x) <= max})
        result = df[logindex, ]
    }

    return(result)
}

8

가정 dat데이터 프레임으로 다음을 사용하여 예상 출력을 얻을 수 있습니다.

1.rowSums

> dat[!rowSums((is.na(dat))),]
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0   2    2    2    2
6 ENSG00000221312    0   1    2    3    2

2.lapply

> dat[!Reduce('|',lapply(dat,is.na)),]
             gene hsap mmul mmus rnor cfam
2 ENSG00000199674    0   2    2    2    2
6 ENSG00000221312    0   1    2    3    2

7

두 장군이고 공정하게 읽을 수있는 코드를 산출 한 가지 방법은 사용하는 filter기능과 dplyr 패키지 그 변종을 ( filter_all, filter_at, filter_if) :

library(dplyr)

vars_to_check <- c("rnor", "cfam")

# Filter a specific list of columns to keep only non-missing entries
df %>% 
  filter_at(.vars = vars(one_of(vars_to_check)),
            ~ !is.na(.))

# Filter all the columns to exclude NA
df %>% 
  filter_all(~ !is.na(.))

# Filter only numeric columns
df %>%
  filter_if(is.numeric,
            ~ !is.na(.))

4
delete.dirt <- function(DF, dart=c('NA')) {
  dirty_rows <- apply(DF, 1, function(r) !any(r %in% dart))
  DF <- DF[dirty_rows, ]
}

mydata <- delete.dirt(mydata)

위 함수는 열에 'NA'가있는 데이터 프레임에서 모든 행을 삭제하고 결과 데이터를 반환합니다. 여러 개의 같은 값을 확인하려면 NA?변경 dart=c('NA')기능 PARAM의에dart=c('NA', '?')


3

내 생각에 이것은이 방법으로보다 우아하게 해결할 수 있다고 생각합니다.

  m <- matrix(1:25, ncol = 5)
  m[c(1, 6, 13, 25)] <- NA
  df <- data.frame(m)
  library(dplyr) 
  df %>%
  filter_all(any_vars(is.na(.)))
  #>   X1 X2 X3 X4 X5
  #> 1 NA NA 11 16 21
  #> 2  3  8 NA 18 23
  #> 3  5 10 15 20 NA

6
이것은로 행을 유지합니다 NA. OP가 원하는 것은 다음과 같습니다.df %>% filter_all(all_vars(!is.na(.)))
asifzuba
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.