Est-il possible de filtrer un data.frame pour des cas complets en utilisant dplyr? complete.cases
avec une liste de toutes les variables fonctionne, bien sûr. Mais c’est a) verbeux quand il y a beaucoup de variables et b) impossible quand les noms des variables ne sont pas connus (par exemple dans une fonction qui traite n’importe quel data.frame).
library(dplyr)
df = data.frame(
x1 = c(1,2,3,NA),
x2 = c(1,2,NA,5)
)
df %.%
filter(complete.cases(x1,x2))
Essaye ça:
df %>% na.omit
ou ca:
df %>% filter(complete.cases(.))
ou ca:
library(tidyr)
df %>% drop_na
Si vous souhaitez filtrer en fonction du caractère manquant d'une variable, utilisez une condition:
df %>% filter(!is.na(x1))
ou
df %>% drop_na(x1)
D'autres réponses indiquent que parmi les solutions ci-dessus na.omit
est beaucoup plus lent, mais il faut tenir compte du fait qu’il renvoie les index des lignes omises dans le na.action
attribut alors que les autres solutions ci-dessus ne le font pas.
str(df %>% na.omit)
## 'data.frame': 2 obs. of 2 variables:
## $ x1: num 1 2
## $ x2: num 1 2
## - attr(*, "na.action")= 'omit' Named int 3 4
## ..- attr(*, "names")= chr "3" "4"
AJOUTÉ Avoir mis à jour pour refléter la dernière version de dplyr et ses commentaires.
AJOUTÉ Avoir mis à jour pour refléter la dernière version de tidyr et des commentaires.
Cela fonctionne pour moi:
df %>%
filter(complete.cases(df))
Ou un peu plus général:
library(dplyr) # 0.4
df %>% filter(complete.cases(.))
Cela aurait l'avantage que les données auraient pu être modifiées dans la chaîne avant de les transmettre au filtre.
Un autre repère avec plus de colonnes:
set.seed(123)
x <- sample(1e5,1e5*26, replace = TRUE)
x[sample(seq_along(x), 1e3)] <- NA
df <- as.data.frame(matrix(x, ncol = 26))
library(microbenchmark)
microbenchmark(
na.omit = {df %>% na.omit},
filter.anonymous = {df %>% (function(x) filter(x, complete.cases(x)))},
rowSums = {df %>% filter(rowSums(is.na(.)) == 0L)},
filter = {df %>% filter(complete.cases(.))},
times = 20L,
unit = "relative")
#Unit: relative
# expr min lq median uq max neval
# na.omit 12.252048 11.248707 11.327005 11.0623422 12.823233 20
#filter.anonymous 1.149305 1.022891 1.013779 0.9948659 4.668691 20
# rowSums 2.281002 2.377807 2.420615 2.3467519 5.223077 20
# filter 1.000000 1.000000 1.000000 1.0000000 1.000000 20
Voici quelques résultats de référence pour la réponse de Grothendieck. na.omit () prend 20 fois plus de temps que les deux autres solutions. Je pense que ce serait bien si dplyr avait une fonction pour cela peut-être en tant que filtre.
library('rbenchmark')
library('dplyr')
n = 5e6
n.na = 100000
df = data.frame(
x1 = sample(1:10, n, replace=TRUE),
x2 = sample(1:10, n, replace=TRUE)
)
df$x1[sample(1:n, n.na)] = NA
df$x2[sample(1:n, n.na)] = NA
benchmark(
df %>% filter(complete.cases(x1,x2)),
df %>% na.omit(),
df %>% (function(x) filter(x, complete.cases(x)))()
, replications=50)
# test replications elapsed relative
# 3 df %.% (function(x) filter(x, complete.cases(x)))() 50 5.422 1.000
# 1 df %.% filter(complete.cases(x1, x2)) 50 6.262 1.155
# 2 df %.% na.omit() 50 109.618 20.217
Ceci est une fonction courte qui vous permet de spécifier des colonnes (essentiellement tout ce que dplyr::select
Peut comprendre) qui ne devraient pas avoir de valeur NA (modélisées selon pandas df.dropna () ):
drop_na <- function(data, ...){
if (missing(...)){
f = complete.cases(data)
} else {
f <- complete.cases(select_(data, .dots = lazyeval::lazy_dots(...)))
}
filter(data, f)
}
[ drop_na fait maintenant partie de tidyr : ce qui précède peut être remplacé par library("tidyr")
]
Exemples:
library("dplyr")
df <- data.frame(a=c(1,2,3,4,NA), b=c(NA,1,2,3,4), ac=c(1,2,NA,3,4))
df %>% drop_na(a,b)
df %>% drop_na(starts_with("a"))
df %>% drop_na() # drops all rows with NAs
essaye ça
df[complete.cases(df),] #output to console
OU même cela
df.complete <- df[complete.cases(df),] #assign to a new data.frame
Les commandes ci-dessus permettent de vérifier l'exhaustivité de toutes les colonnes (variable) de votre data.frame.
Juste pour être complet, dplyr::filter
peut être évité tout en étant capable de composer des chaînes simplement en utilisant magrittr:extract
(un alias de [
):
library(magrittr)
df = data.frame(
x1 = c(1,2,3,NA),
x2 = c(1,2,NA,5))
df %>%
extract(complete.cases(.), )
Le bonus supplémentaire est la vitesse, c'est la méthode la plus rapide parmi les filter
et na.omit
variantes (testé avec les micro-repères de @Miha Trošt).