1
votes

Filtrer les lignes contenant une certaine chaîne dans toutes les colonnes (avec dplyr)

J'ai les données suivantes:

Error: Problem with `filter()` input `..1`.
x Input `..1$name1` must be a logical vector, not a character.
i Input `..1` is `across(everything())`.
data %>%
  filter(across(everything()), !str.detect("John"))

Je souhaite filtrer toutes les lignes contenant la chaîne "John" sur toutes les colonnes (le nombre de colonnes peut être supérieur à 3).

J'essaye ce qui suit

> data
          name1      name2        name3
1    John Smith        A V John Donovan
2           A A John Smith          A R
3           A B        A D John Donovan
4           A C        A R          A L
5  John Donovan        A O          A V
6           A F John Smith          A Q
7           A D        A M          A T
8           A F        A V          A N
9           A D        A L          A L
10          A C        A Q          A X

Cependant cela ne fonctionne pas et cela produit:

data <- data.frame(name1 =c("John Smith", "A A", "A B", "A C", "John Donovan", "A F", "A D", "A F", "A D", "A C"),
      name2 = c("A V", "John Smith", "A D", "A R", "A O", "John Smith", "A M", "A V", "A L", "A Q"),
      name3 = c("John Donovan", "A R", "John Donovan", "A L", "A V", "A Q", "A T", "A N", "A L", "A X"))

Avez-vous une idée, en particulier celle qui utilise la fonction across.


0 commentaires

3 Réponses :


2
votes

filter prend un vecteur logique, donc lors de l'utilisation de across, vous devez passer la fonction à l'appel across pour appliquer cette fonction à toutes les colonnes sélectionnées:

 df %>% filter(print(across(everything(), ~ str_detect(., "John"))))
# A tibble: 10 x 3
   V1    V2    V3   
   <lgl> <lgl> <lgl>
 1 TRUE  FALSE TRUE 
 2 FALSE TRUE  FALSE
 3 FALSE FALSE TRUE 
 4 FALSE FALSE FALSE
 5 TRUE  FALSE FALSE
 6 FALSE TRUE  FALSE
 7 FALSE FALSE FALSE
 8 FALSE FALSE FALSE
 9 FALSE FALSE FALSE
10 FALSE FALSE FALSE
[1] V1 V2 V3
<0 rows> (or 0-length row.names)
df %>% filter(print(across(everything(), ~ !str_detect(., "John"))))
# A tibble: 10 x 3
   V1    V2    V3   
   <lgl> <lgl> <lgl>
 1 FALSE TRUE  FALSE
 2 TRUE  FALSE TRUE 
 3 TRUE  TRUE  FALSE
 4 TRUE  TRUE  TRUE 
 5 FALSE TRUE  TRUE 
 6 TRUE  FALSE TRUE 
 7 TRUE  TRUE  TRUE 
 8 TRUE  TRUE  TRUE 
 9 TRUE  TRUE  TRUE 
10 TRUE  TRUE  TRUE 
   V1  V2  V3
1 A C A R A L
2 A D A M A T
3 A F A V A N
4 A D A L A L
5 A C A Q A X

en utilisant la solution proposée dans le commentaire de @ekoam :

            V1         V2           V3
1   John Smith        A V John Donovan
2          A A John Smith          A R
3          A B        A D John Donovan
4 John Donovan        A O          A V
5          A F John Smith          A Q
df %>% filter(rowSums(across(everything(), ~ str_detect(., "John"))) > 0)

Juste pour rendre l'image un peu plus claire:

   V1  V2  V3
1 A C A R A L
2 A D A M A T
3 A F A V A N
4 A D A L A L
5 A C A Q A X

Notez que le filtre est & (et) ing les booléens par ligne, c'est-à-dire que seules les lignes avec toutes les valeurs TRUE seront sélectionnées, celles qui ont au moins un FALSE ne le seront pas. Jetons maintenant un œil au code que vous avez fourni dans votre commentaire:

df %>% filter(across(everything(), ~ !str_detect(., "John")))

Toutes les lignes ont au moins un FALSE , donc aucune ligne n'est sélectionnée.


3 commentaires

Que faire si je veux trouver les lignes qui contiennent la chaîne John. Cela ne fonctionne pas: df%>% filter (across (tout (), ~ str_detect (., "John"))) Savez-vous pourquoi?


Pour filtrer toute colonne contenant "John", effectuez ce data %>% filter(rowSums(across(everything(), ~str_detect(., "John"))) > 0) . @senad


@senad votre code vérifie essentiellement si toutes les colonnes contiennent John . Le commentaire de @ ekoam est correct car il vérifie si au moins une colonne contient John



1
votes

Voici quelques approches de base R.

En utilisant sapply :

df[!Reduce(`|`, lapply(df, grepl, pattern = 'John')), ]

Avec lapply :

df[rowSums(sapply(df, grepl, pattern = 'John')) == 0, ]

#   name1 name2 name3
#4    A C   A R   A L
#7    A D   A M   A T
#8    A F   A V   A N
#9    A D   A L   A L
#10   A C   A Q   A X


2 commentaires

Merci Ronak. avez-vous une idée du commentaire sur la solution d'Abdessabour?


Vous pouvez utiliser df[rowSums(sapply(df, grepl, pattern = 'John')) > 0, ]



1
votes

Nous pouvons également le faire de manière vectorisée

#     name1 name2 name3
#4    A C   A R   A L
#7    A D   A M   A T
#8    A F   A V   A N
#9    A D   A L   A L
#10   A C   A Q   A X

-production

data[!rowSums(`dim<-`(grepl('John', as.matrix(data)), dim(data))),]


0 commentaires