2 votes

Comment extraire des modèles de chaînes spécifiques dans une instruction case_when à l'aide d'expressions régulières ?

Considérons l'ensemble de données reproductible suivant, que j'ai créé sur la base de l'ensemble de données Donald Trump-Tweets (que l'on peut trouver à l'adresse suivante aquí ):

df <- tibble(target = c(rep("jeb-bush", 2), rep("jeb-bush-supporters", 2),
                        "jeb-staffer", rep("the-media", 5)),
             tweet_id = seq(1, 10, 1))

Il se compose de deux colonnes, le groupe cible des tweets et le tweet_id :

# A tibble: 10 x 2
   target              tweet_id
   <chr>                  <dbl>
 1 jeb-bush                   1
 2 jeb-bush                   2
 3 jeb-bush-supporters        3
 4 jeb-bush-supporters        4
 5 jeb-staffer                5
 6 the-media                  6
 7 the-media                  7
 8 the-media                  8
 9 the-media                  9
10 the-media                 10

Objectif :

Chaque fois qu'un élément dans target commence par jeb je veux extraire la chaîne de caractères après le motif - . Et quand il y a plusieurs - dans un élément qui commence par jeb je veux extraire la chaîne de caractères après le DERNIER - (ce qui, dans cet exemple d'ensemble de données, ne serait que le cas pour jeb-bush-supporters ). Pour chaque élément qui ne commence pas par jeb Je veux juste créer la chaîne other . Au final, cela devrait ressembler à ceci :

# A tibble: 10 x 3
   target              tweet_id new_var   
   <chr>                  <dbl> <chr>     
 1 jeb-bush                   1 bush      
 2 jeb-bush                   2 bush      
 3 jeb-bush-supporters        3 supporters
 4 jeb-bush-supporters        4 supporters
 5 jeb-staffer                5 staffer   
 6 the-media                  6 other     
 7 the-media                  7 other     
 8 the-media                  8 other     
 9 the-media                  9 other     
10 the-media                 10 other    

Ce que j'ai essayé :

J'ai réussi à créer le résultat souhaité avec le code suivant :

df %>% 
    mutate(new_var = case_when(str_detect(target, "^jeb-[a-z]+$") ~
                             str_extract(target, "(?<=[a-z]{3}-)[a-z]+"),
                               str_detect(target, "^jeb-[a-z]+-[a-z]+") ~
                             str_extract(target, "(?<=[a-z]{3}-[a-z]{4}-)[a-z]+"),
                               TRUE ~ "other"))

Mais le problème est le suivant :

Dans le deuxième str_extract je dois définir le nombre exact de lettres dans la déclaration "Positive Look Behind" ( [a-z]{4} ). Sinon, R se plaint d'avoir besoin d'une "longueur maximale bornée". Mais que faire si je ne connais pas la longueur exacte du motif ou si elle varie d'un élément à l'autre ?

Par ailleurs, j'ai essayé de travailler avec des groupes de capture plutôt qu'avec des "Look Arounds". J'ai donc essayé d'inclure str_match pour définir ce que je veux extraire au lieu de ce que je ne veux pas extraire :

df %>% 
    mutate(new_var = case_when(str_detect(target, "^jeb-[a-z]+$") ~
                             str_match(target, "jeb-([a-z]+)"),
                           str_detect(target, "^jeb-[a-z]+-[a-z]+") ~
                             str_match(target, "jeb-[a-z]+-([a-z]+)"),
                           TRUE ~ "other"))

Mais ensuite, je reçois ce message d'erreur :

Error: Problem with `mutate()` input `new_var`.
x `str_detect(target, "^jeb-[a-z]+$") ~ str_match(target, "jeb-([a-z]+)")`, `str_detect(target, "^jeb-[a-z]+-[a-z]+") ~ str_match(target, 
    "jeb-[a-z]{4}-([a-z]+)")` must be length 10 or one, not 20.
i Input `new_var` is `case_when(...)`.

Question :

En fin de compte, je veux savoir s'il existe un moyen concis d'extraire des modèles de chaîne spécifiques dans une déclaration case_when. Comment pourrais-je contourner le problème que j'ai énoncé ici, lorsque je ne serais pas en mesure d'utiliser les "Look Arounds" (parce que je ne peux pas définir une longueur maximale limitée) ni les groupes de capture (parce que str_match retournerait un vecteur de longueur 20 et non de la taille originale 10 ou un) ?

3voto

akrun Points 148302

Une option est de vérifier la colonne cible avec la sous-chaîne 'jeb-' depuis le début ( ^ ) de la chaîne de caractères dans case_when puis extraire les caractères qui ne sont pas un - ( [^-]+ ) à la fin ( $ ) de la chaîne, ou sinon ( TRUE ) retourner l'"autre".

library(dplyr)
library(stringr)
df %>% 
    mutate(new_var = case_when(str_detect(target, '^jeb-')~ 
        str_extract(target, '[^-]+$'), TRUE ~ 'other'))

-sortie

# A tibble: 10 x 3
#   target              tweet_id new_var   
#   <chr>                  <dbl> <chr>     
# 1 jeb-bush                   1 bush      
# 2 jeb-bush                   2 bush      
# 3 jeb-bush-supporters        3 supporters
# 4 jeb-bush-supporters        4 supporters
# 5 jeb-staffer                5 staffer   
# 6 the-media                  6 other     
# 7 the-media                  7 other     
# 8 the-media                  8 other     
# 9 the-media                  9 other     
#10 the-media                 10 other    

Nous pouvons aussi simplifier cela avec str_match y coalesce

df %>% 
   mutate(new_var = coalesce(str_match(target, '^jeb-.*?([^-]+)$')[,2], 'other'))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X