Hapus kolom dari kerangka data di mana SEMUA nilai adalah NA


149

Saya mengalami masalah dengan kerangka data dan saya sendiri tidak bisa menyelesaikan masalah itu:
Kerangka data memiliki sifat sewenang-wenang sebagai kolom dan setiap baris mewakili satu set data .

Pertanyaannya adalah:
Bagaimana cara menyingkirkan kolom di mana untuk SEMUA baris nilainya NA ?

Jawaban:


155

Coba ini:

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

3
Ini menciptakan objek ukuran objek lama yang merupakan masalah dengan memori pada objek besar. Lebih baik menggunakan fungsi untuk mengurangi ukuran. Jawabannya di bawah ini menggunakan Filter atau menggunakan data.tabel akan membantu penggunaan memori Anda.
mtelesha

3
Tampaknya ini tidak berfungsi dengan kolom non-numerik.
verbamour

Itu mengubah nama kolom jika mereka digandakan
Peter.k

97

Dua pendekatan yang ditawarkan sejauh ini gagal dengan set data besar sebagai (di antara masalah memori lainnya) yang mereka buat is.na(df), yang akan menjadi objek dengan ukuran yang sama df.

Berikut adalah dua pendekatan yang lebih hemat memori dan waktu

Pendekatan menggunakan Filter

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

dan pendekatan menggunakan data.table (untuk efisiensi waktu dan memori umum)

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

contoh menggunakan data besar (30 kolom, 1e6 baris)

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
Sangat bagus. Anda bisa melakukan hal yang sama dengannya data.frame. Tidak ada yang perlu di sini data.table. Kuncinya adalah lapply, yang menghindari salinan seluruh objek yang dilakukan oleh is.na(df). +10 untuk menunjukkannya.
Matt Dowle

1
Bagaimana Anda melakukannya dengan data.frame? @ matt-dowle
s_a

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

6
@mnel Saya pikir Anda perlu menghapus ,setelah function(x)- terima kasih untuk contoh btw
Thieme Hennis

1
Bisakah Anda melakukannya lebih cepat dengan: = atau dengan set ()?
skan

49

dplyrsekarang memiliki select_ifkata kerja yang mungkin berguna di sini:

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

Datang ke sini mencari dplyrsolusinya. Tidak kecewa. Terima kasih!
Andrew Brēza

Saya menemukan ini memiliki masalah yang juga akan menghapus variabel dengan sebagian besar tetapi tidak semua nilai hilang
MBorg

15

Cara lain adalah dengan menggunakan apply()fungsi tersebut.

Jika Anda memiliki data.frame

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

maka Anda dapat menggunakan apply()untuk melihat kolom mana yang memenuhi kondisi Anda dan sehingga Anda dapat melakukan subsetting yang sama seperti dalam jawaban oleh Musa, hanya dengan applypendekatan.

> !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
Saya berharap ini lebih cepat, karena solusi colSum () tampaknya melakukan lebih banyak pekerjaan. Tetapi pada set pengujian saya (213 obs. 1614 variabel sebelumnya, vs 1377 variabel sesudahnya) dibutuhkan tepat 3 kali lebih lama. (Tapi +1 untuk pendekatan yang menarik.)
Darren Cook

10

Terlambat ke permainan tetapi Anda juga dapat menggunakan janitorpaket. Fungsi ini akan menghapus kolom yang semuanya NA, dan dapat diubah untuk menghapus baris yang semuanya NA juga.

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



4

Jawaban yang diterima tidak berfungsi dengan kolom non-numerik. Dari jawaban ini , berikut ini berfungsi dengan kolom yang berisi tipe data berbeda

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

Orang lain telah memposting jawaban yang sama di utas ini 4 tahun sebelum Anda ... Lihat jawaban mnel di bawah ini.
André.B

2

Opsi lain dengan purrrpaket:

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

Saya harap ini juga dapat membantu. Itu bisa dibuat menjadi satu perintah, tetapi saya merasa lebih mudah bagi saya untuk membaca dengan membaginya dalam dua perintah. Saya membuat fungsi dengan instruksi berikut dan bekerja dengan cepat.

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

.SD akan memungkinkan untuk membatasi verifikasi menjadi bagian dari tabel, jika Anda mau, tetapi akan menjadikan seluruh tabel sebagai


1

Pilihan praktis base Rbisa berupa colMeans():

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

0

Anda dapat menggunakan paket Petugas Kebersihan remove_empty

library(janitor)

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

Juga, pendekatan dplyr lain

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

ATAU

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

ini juga berguna jika Anda hanya ingin mengecualikan / menyimpan kolom dengan sejumlah nilai yang hilang misalnya

 df %>% select_if(colSums(!is.na(.))>500)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.