TÜM değerlerin NA olduğu veri çerçevesinden sütunları kaldırma


149

Bir veri çerçevesi ile ilgili sorun yaşıyorum ve gerçekten bu konuyu kendim çözemedi: dataframe keyfi vardır sütunlar olarak özelliklerini ve her satır birini temsil veri kümesini .

Soru şudur: TÜM satırlar için değer NA olan sütunlardan
nasıl kurtulurum ?

Yanıtlar:


155

Bunu dene:

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

3
Bu, büyük nesnelerdeki bellekle ilgili bir sorun olan eski nesnenin boyutunda bir nesne oluşturur. Boyutu azaltmak için bir işlev kullanmak daha iyidir. Filtre veya data.table kullanarak cevap, bellek kullanımınıza yardımcı olacaktır.
mtelesha

3
Bu sayısal olmayan sütunlarla çalışıyor gibi görünmüyor.
verbamour

Çoğaltılırlarsa sütun adını değiştirir
Peter.k

98

Şu ana kadar sunulan iki yaklaşım, oluşturdukları büyük veri kümeleriyle (diğer bellek sorunlarının yanı sıra) is.na(df), aynı boyutta bir nesne olacak şekilde başarısız olmaktadır df.

İşte daha fazla bellek ve zamandan tasarruf sağlayan iki yaklaşım

Kullanarak bir yaklaşım Filter

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

ve data.table kullanan bir yaklaşım (genel zaman ve bellek verimliliği için)

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

büyük veri kullanan örnekler (30 sütun, 1e6 satır)

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
Çok hoş. data.frameYine de aynısını yapabilirsiniz . Burada gerçekten ihtiyacı olan hiçbir şey yok data.table. Anahtar, lapplytarafından yapılan tüm nesnenin kopyasını önleyen anahtardır is.na(df). İşaret etmek için +10.
Matt Dowle

1
Bir data.frame ile nasıl yapardınız? @ matt-dowle
s_a

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

6
@mnel Sanırım ,sonra kaldırmak gerekir function(x)- örnek btw için teşekkürler
Thieme Hennis

1
: = Veya bir set () ile daha hızlı yapabilir misiniz?
skan

49

dplyrşimdi select_ifburada yardımcı olabilecek bir fiil var:

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

Buraya dplyrçözüm arıyor . Hayal kırıklığına uğradım. Teşekkürler!
Andrew Brēza

Ben de tüm değerleri eksik olarak değil, en çok değişkenleri de silme sorunu olduğunu buldum
MBorg

15

Başka bir yol apply()işlevi kullanmak olabilir .

Data.frame'iniz varsa

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

apply()hangi sütunların durumunuzu karşıladığını görmek için kullanabilirsiniz ve böylece Musa'nın cevabındakiyle aynı alt ayarı sadece bir applyyaklaşımla yapabilirsiniz.

> !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 () çözümü daha fazla iş yapıyor gibi görünüyordu, bu daha hızlı olması bekleniyor. Ancak test setimde (daha önce 1614 değişkenin 213 obs, daha sonra 1377 değişken) tam olarak 3 kat daha uzun sürüyor. (Ama ilginç bir yaklaşım için +1.)
Darren Cook

10

Oyuna geç ama janitorpaketi de kullanabilirsiniz . Bu işlev, tüm NA olan sütunları kaldırır ve tüm NA olan satırları da kaldırmak için değiştirilebilir.

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



4

Kabul edilen cevap sayısal olmayan sütunlarla çalışmaz. Gönderen Bu yanıt , şu farklı veri türlerini içeren sütunlar ile çalışır

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

Birisi sizden 4 yıl önce bu cevapta zaten aynı cevabı gönderdi ... Aşağıdaki mnel'in cevabına bakınız.
André.B

2

Paketli başka seçenekler 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

Umarım bu da yardımcı olabilir. Tek bir komut haline getirilebilirdi, ama okumayı iki komuta ayırarak daha kolay buldum. Aşağıdaki talimatla bir işlev yaptım ve yıldırım hızında çalıştım.

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

.SD, doğrulamayı dilerseniz tablonun bir bölümü ile sınırlandırır, ancak tüm tabloyu aşağıdaki gibi alır


1

Kullanışlı bir base Rseçenek şunlar olabilir colMeans():

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

0

Kapıcı paketini kullanabilirsiniz remove_empty

library(janitor)

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

Ayrıca, Başka bir dplyr yaklaşımı

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

VEYA

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

bu, yalnızca belirli sayıda eksik değere sahip sütunu hariç tutmak / tutmak istiyorsanız, örn.

 df %>% select_if(colSums(!is.na(.))>500)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.