डेटाफ़्रेम से कॉलम निकालें जहाँ सभी मान NA हैं


149

मैं एक डेटा फ्रेम में परेशानी आ रही है और वास्तव में अपने आप को कि इस मुद्दे को हल नहीं कर सका: dataframe मनमाना है स्तंभों के रूप में गुण और प्रत्येक पंक्ति एक का प्रतिनिधित्व करता डेटा सेट

सवाल यह है: जहां सभी पंक्तियों के लिए कॉलम एनए से
कैसे छुटकारा पाएं ?

जवाबों:


155

इसे इस्तेमाल करे:

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

3
यह एक ऑब्जेक्ट को पुरानी वस्तु का आकार बनाता है जो बड़ी वस्तुओं पर मेमोरी के साथ एक समस्या है। आकार को कम करने के लिए एक फ़ंक्शन का उपयोग करना बेहतर है। फ़िल्टर का उपयोग करके या data.table का उपयोग करके उत्तर bellow आपकी स्मृति उपयोग में मदद करेगा।
mtelesha

3
यह गैर-संख्यात्मक कॉलम के साथ काम नहीं करता है।
क्रिया

यदि वे डुप्लिकेट हैं, तो यह कॉलम का नाम बदल देता है
पीटर।

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 उस ओर इशारा करते हुए।
मैट डोले

1
आप इसे डेटा.फ्रेम के साथ कैसे करेंगे? @ मैट-डॉवेल
s_a

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

6
@ मुझे लगता है कि आपको इसके ,बाद हटाने की आवश्यकता है function(x)- उदाहरण के लिए धन्यवाद btw
थिएम हनिस

1
क्या आप इसे तेजी से कर सकते हैं: = या एक सेट () के साथ?
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समाधान की तलाश में यहां आया था । निराश नहीं हुआ था। धन्यवाद!
एंड्रयू ब्रूजा

मैंने पाया कि यह मुद्दा था कि यह चर को भी गायब कर देगा लेकिन सभी मूल्यों को गायब नहीं करेगा
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दृष्टिकोण के साथ ।

> !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
मुझे उम्मीद थी कि यह जल्दी होगा, क्योंकि कॉलसम () समाधान अधिक काम कर रहा था। लेकिन मेरे परीक्षण सेट पर (पहले 1614 चर का 213 अवलोकन, बनाम 1377 चर) बाद में इसे 3 गुना अधिक समय लगता है। (लेकिन दिलचस्प दृष्टिकोण के लिए +1)
डैरेन कुक

10

खेल के लिए देर हो चुकी है लेकिन आप janitorपैकेज का उपयोग भी कर सकते हैं । यह फ़ंक्शन उन स्तंभों को हटा देगा जो सभी NA हैं, और उन पंक्तियों को हटाने के लिए बदला जा सकता है जो सभी NA हैं।

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



4

स्वीकृत उत्तर गैर-संख्यात्मक कॉलम के साथ काम नहीं करता है। से इस उत्तर , निम्नलिखित विभिन्न डेटा प्रकार युक्त कॉलम के साथ काम करता है

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

किसी और ने आपके द्वारा 4 साल पहले ही इस धागे में एक ही उत्तर पोस्ट किया है ... नीचे दिए गए मेल का जवाब देखें।
एंड्रे.बी

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

आप Janitor पैकेज का उपयोग कर सकते हैं remove_empty

library(janitor)

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

इसके अलावा, एक और साहसी दृष्टिकोण

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

या

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

यह भी उपयोगी है यदि आप कुछ निश्चित मानों के साथ कॉलम को केवल बाहर करना / रखना चाहते हैं जैसे

 df %>% select_if(colSums(!is.na(.))>500)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.