Câu trả lời:
Thử cái này:
df <- df[,colSums(is.na(df))<nrow(df)]
Hai cách tiếp cận được cung cấp cho đến nay thất bại với các tập dữ liệu lớn là (trong số các vấn đề bộ nhớ khác) mà chúng tạo ra is.na(df)
, sẽ là một đối tượng có cùng kích thước df
.
Đây là hai cách tiếp cận hiệu quả hơn về bộ nhớ và thời gian
Một cách tiếp cận bằng cách sử dụng Filter
Filter(function(x)!all(is.na(x)), df)
và một cách tiếp cận bằng cách sử dụng data.table (cho hiệu quả thời gian và bộ nhớ chung)
library(data.table)
DT <- as.data.table(df)
DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]
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
data.frame
, mặc dù. Không có gì ở đây thực sự cần data.table
. Điều quan trọng là lapply
, trong đó tránh bản sao của toàn bộ đối tượng được thực hiện bởi is.na(df)
. +10 để chỉ ra điều đó.
bd1 <- bd[, unlist(lapply(bd, function(x), !all(is.na(x))))]
,
sau function(x)
- cảm ơn vì ví dụ btw
dplyr
bây giờ có một select_if
động từ có thể hữu ích ở đây:
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
giải pháp. Đã không thất vọng. Cảm ơn!
Một cách khác là sử dụng apply()
chức năng.
Nếu bạn có data.frame
df <- data.frame (var1 = c(1:7,NA),
var2 = c(1,2,1,3,4,NA,NA,9),
var3 = c(NA)
)
sau đó bạn có thể sử dụng apply()
để xem cột nào đáp ứng điều kiện của bạn và do đó bạn chỉ cần thực hiện cùng một tập hợp con như trong câu trả lời của Musa, chỉ với một apply
cách tiếp cận.
> !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
Câu trả lời được chấp nhận không hoạt động với các cột không phải là số. Từ câu trả lời này , các công việc sau đây với các cột chứa các loại dữ liệu khác nhau
Filter(function(x) !all(is.na(x)), df)
Tôi hy vọng điều này cũng có thể giúp đỡ. Nó có thể được tạo thành một lệnh duy nhất, nhưng tôi thấy nó dễ đọc hơn bằng cách chia nó thành hai lệnh. Tôi đã thực hiện một chức năng với hướng dẫn sau đây và làm việc nhanh như chớp.
naColsRemoval = function (DataTable) {
na.cols = DataTable [ , .( which ( apply ( is.na ( .SD ) , 2 , all ) ) )]
DataTable [ , unlist (na.cols) := NULL , with = F]
}
.SD sẽ cho phép giới hạn xác minh ở một phần của bảng, nếu bạn muốn, nhưng nó sẽ lấy toàn bộ bảng dưới dạng
Bạn có thể sử dụng gói Janitor remove_empty
library(janitor)
df %>%
remove_empty(c("rows", "cols")) #select either row or cols or both
Ngoài ra, một cách tiếp cận dplyr khác
library(dplyr)
df %>% select_if(~all(!is.na(.)))
HOẶC LÀ
df %>% select_if(colSums(!is.na(.)) == nrow(df))
điều này cũng hữu ích nếu bạn muốn chỉ loại trừ / giữ cột với số lượng giá trị bị thiếu nhất định, vd
df %>% select_if(colSums(!is.na(.))>500)