Data.frame में सभी या कुछ NA (लापता मान) वाली पंक्तियाँ निकालें


851

मैं इस डेटा फ़्रेम में लाइनें निकालना चाहता हूं:

क) शामिल 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

ख) शामिल 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सिर्फ सभी को हटाने के लिए अच्छा है NAcomplete.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),]?
हर्त्ज़प्रसंग

6
@hertzsprung आपको पंक्तियों का चयन करने की आवश्यकता है, न कि कॉलम की। आप और कैसे करेंगे?
जोरिस मेस

4
वहाँ का एक सरल निषेध है complete.cases? अगर मैं छोड़ने के बजाय NA के साथ पंक्तियों को रखना चाहता था? final[ ! complete.cases(final),]सहयोग नहीं करता है ...
tumultous_rooster

2
finalडेटाफ्रेम चर है?
मोर्स

1
@ सच में, यह है।
जोरिस मेय्स

256

कोशिश करो na.omit(your.data.frame)। दूसरे प्रश्न के लिए, इसे दूसरे प्रश्न के रूप में पोस्ट करने का प्रयास करें (स्पष्टता के लिए)।


na.omit पंक्तियों को छोड़ता है लेकिन पंक्ति संख्याओं को संरक्षित करता है। आप इसे कैसे ठीक करेंगे ताकि इसे ठीक से गिना जाए?
भालू

3
@ यदि आप पंक्ति संख्या की परवाह नहीं करते हैं, तो बस करें rownames(x) <- NULL
रोमन लुसट्रिक

कृपया ध्यान दें कि किसी भी कॉलम 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)सभी मूल रूप से बराबर हैं।
इस्टा

4
@ इस्टा मैं असहमत हूं। na.omitलोप किए गए मामलों के सूचकांकों की तरह अतिरिक्त जानकारी जोड़ता है, और - और अधिक महत्वपूर्ण बात - आपको स्तंभों का चयन करने की अनुमति नहीं देता है - यह वह जगह है जहां drop_naचमकता है।
ल्यूका

3
निश्चित रूप से, मेरा कहना है कि गैर का पाइप से कोई लेना-देना नहीं है। आप na.omitपाइप के साथ या बिना उपयोग कर सकते हैं , जैसे आप drop_naपाइप के साथ या बिना उपयोग कर सकते हैं ।
इस्टा

1
सच है, पाइप के साथ कुछ भी नहीं करना है। drop_na () किसी भी अन्य की तरह एक फ़ंक्शन है और, जैसे, सीधे पाइप का उपयोग करके कहा जा सकता है। दुर्भाग्य से, drop_na (), अन्य उल्लिखित विधियों के विपरीत, चिड़ियाघर या xts ऑब्जेक्ट प्रकारों पर उपयोग नहीं किया जा सकता है। यह कुछ के लिए एक समस्या हो सकती है।
डेव

ठीक है, इसलिए मैंने उत्तर को संपादित किया ताकि पाइप का उल्लेख न हो।
आर्थर यिप

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 के कुछ भाग के साथ पंक्तियों को फ़िल्टर करने के लिए यह थोड़ा पेचीदा हो जाता है (उदाहरण के लिए, आप 'अंतिम [, 5: 6]' को 'लागू' कर सकते हैं)। आमतौर पर, जोरिस मेय्स का समाधान अधिक सुरुचिपूर्ण लगता है।


2
यह बेहद धीमी है। पूर्व की तुलना में बहुत धीमी गति से। पूरा पूरा। () समाधान। कम से कम, मेरे मामले में, एक्सटीएस डेटा पर।
डेव

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 को हटा दिया जाता है क्योंकि यह एकमात्र पंक्ति है जिसमें NA rnorऔर दोनों के लिए NA है cfam। विशिष्ट आवश्यकताओं को पूरा करने के लिए बूलियन तर्क को बदला जा सकता है।


5
लेकिन आप इसका उपयोग कैसे कर सकते हैं यदि आप कई कॉलमों की जांच करना चाहते हैं, तो हर एक को टाइप किए बिना, क्या आप एक रेंज फाइनल [, 4: 100] का उपयोग कर सकते हैं?
हरमन टूथ्रोट

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.tableऔर na.omit()वैकल्पिक परम के साथ cols=

na.omit.data.table मेरे बेंचमार्क पर सबसे तेज़ है (नीचे देखें), चाहे सभी कॉलम के लिए या चुनिंदा कॉलम के लिए (ओपी प्रश्न भाग 2)।

यदि आप उपयोग नहीं करना चाहते हैं data.table, तो उपयोग करें complete.cases()

एक वेनिला पर data.frame, complete.casesसे तेज na.omit()या है dplyr::drop_na()। नोटिस जो na.omit.data.frameसमर्थन नहीं करता है cols=

बेंचमार्क परिणाम

यहां आधार (नीली), dplyr(गुलाबी), और data.table(पीले) तरीकों की तुलना या तो सभी को छोड़ने की है या लापता टिप्पणियों का चयन करें, स्वतंत्र होने की 5% संभावना के साथ 20 संख्यात्मक चर के 1 मिलियन टिप्पणियों के नोटिफ़िक डेटासेट पर, और लापता होने की संभावना है। भाग 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()
ज़िमानो

17

यह उन पंक्तियों को लौटा देगा जिनमें कम से कम एक गैर-एनए मान है।

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

यह उन पंक्तियों को लौटा देगा जिनमें कम से कम दो गैर-एनए मूल्य हैं।

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

16

आपके पहले प्रश्न के लिए, मेरे पास एक कोड है जिसे मैं सभी NA से छुटकारा पाने के लिए सहज हूं। @ सरल बनाने के लिए धन्यवाद।

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

दूसरे प्रश्न के लिए, कोड पिछले समाधान से केवल एक वैकल्पिक है।

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

सूचना -5 आपके डेटा में कॉलम की संख्या है। यह सभी NA के साथ पंक्तियों को समाप्त कर देगा, क्योंकि rowSums 5 तक जोड़ता है और वे घटाव के बाद शून्य हो जाते हैं। इस बार, as.logical आवश्यक है।


अंतिम [as.logical ((rowSums (is.na (अंतिम)) - ncol (अंतिम)),] एक सार्वभौमिक उत्तर के लिए
फेरो

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')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। मुझे लगता है कि ओपी क्या चाहता है:df %>% filter_all(all_vars(!is.na(.)))
asifzuba
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.