Risposte:
Prova questo:
df <- df[,colSums(is.na(df))<nrow(df)]
I due approcci offerti finora falliscono con set di dati di grandi dimensioni come (tra gli altri problemi di memoria) che creano is.na(df)
, che sarà un oggetto delle stesse dimensioni di df
.
Ecco due approcci che sono più efficienti in termini di memoria e tempo
Un approccio che utilizza Filter
Filter(function(x)!all(is.na(x)), df)
e un approccio che utilizza data.table (per tempo generale ed efficienza della memoria)
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
, comunque. Non c'è niente qui che ha davvero bisogno data.table
. La chiave è la lapply
, che evita la copia dell'intero oggetto fatto da is.na(df)
. +10 per evidenziarlo.
bd1 <- bd[, unlist(lapply(bd, function(x), !all(is.na(x))))]
,
dopo function(x)
- grazie per l'esempio tra l'altro
dplyr
ora ha un select_if
verbo che può essere utile qui:
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
soluzione. Non sono rimasto deluso. Grazie!
Un altro modo sarebbe usare la apply()
funzione.
Se si dispone di data.frame
df <- data.frame (var1 = c(1:7,NA),
var2 = c(1,2,1,3,4,NA,NA,9),
var3 = c(NA)
)
quindi puoi usare apply()
per vedere quali colonne soddisfano la tua condizione e quindi puoi semplicemente fare lo stesso sottoinsieme della risposta di Musa, solo con un apply
approccio.
> !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
La risposta accettata non funziona con colonne non numeriche. Da questa risposta , quanto segue funziona con colonne contenenti diversi tipi di dati
Filter(function(x) !all(is.na(x)), df)
Spero che questo possa anche aiutare. Potrebbe essere trasformato in un singolo comando, ma ho trovato più facile da leggere dividendolo in due comandi. Ho fatto una funzione con le seguenti istruzioni e ho lavorato velocemente.
naColsRemoval = function (DataTable) {
na.cols = DataTable [ , .( which ( apply ( is.na ( .SD ) , 2 , all ) ) )]
DataTable [ , unlist (na.cols) := NULL , with = F]
}
.SD consentirà di limitare la verifica a parte della tabella, se lo si desidera, ma prenderà l'intera tabella come
Puoi usare il pacchetto Janitor remove_empty
library(janitor)
df %>%
remove_empty(c("rows", "cols")) #select either row or cols or both
Inoltre, un altro approccio dplyr
library(dplyr)
df %>% select_if(~all(!is.na(.)))
O
df %>% select_if(colSums(!is.na(.)) == nrow(df))
questo è utile anche se si desidera escludere / mantenere la colonna con un determinato numero di valori mancanti, ad es
df %>% select_if(colSums(!is.na(.))>500)