Considérez un tibble où chaque colonne est un vecteur de caractères qui peut prendre plusieurs valeurs - disons "A" à "F".
library(tidyverse)
sample_df <- tibble(q1 = c("A", "B", "C"), q2 = c("B", "B", "A"))
Je souhaite créer une fonction qui prend un nom de colonne comme argument et recode cette colonne de sorte que toute réponse "A" devienne une NA et que le df soit retourné tel quel. La raison de sa conception de cette manière est de s'intégrer dans un pipeline plus large qui effectue une série d'opérations à l'aide d'une colonne donnée.
Il existe plusieurs façons de procéder. Mais je suis intéressé à comprendre quelle serait la meilleure approche idiomatique tidy_eval / tidyverse. Tout d'abord, le nom de la question doit être à gauche d'un verbe muté, nous utilisons donc les opérateurs !!
et de :=
manière appropriée. Mais alors, que mettre du côté droit?
fix_question <- function(df, question) {
df %>% mutate(!!question := recode(... something goes here...))
}
fix_question(sample_df, "q1") # should produce a tibble whose first column is (NA, "B", "C")
Ma pensée initiale était que cela fonctionnerait:
df %>% mutate(!!question := recode(!!question, "A" = NA_character_))
Mais bien sûr, le bang-bang à l'intérieur de la fonction renvoie juste la chaîne de caractères littérale (par exemple "q1"). J'ai fini par prendre ce qui ressemble à une route hacky pour référencer les données sur le côté droit, en utilisant l' [[
opérateur de base R et en s'appuyant sur la .
construction de dplyr, et cela fonctionne, donc dans un sens, j'ai résolu mon problème sous-jacent:
df %>% mutate(!!question := recode(.[[question]], "A" = NA_character_))
Je suis intéressé à obtenir des commentaires de personnes très douées pour savoir s'il existe une façon plus idiomatique de le faire, dans l'espoir que voir un exemple concret améliorerait ma compréhension de l'ensemble des fonctions de rangement. Des pensées?
q1
(symbole) et"q1"
(chaîne):df %>% mutate_at( vars(!!ensym(question)), recode, A = NA_character_)
Réponses:
Ici, sur le côté droit de
:=
, nous pouvons spécifiersym
de convertir en symbole puis d'évaluer (!!
)Une meilleure approche qui fonctionnerait pour les entrées cotées et non cotées est
ensym
la source
Vous pouvez utiliser la méthode "curly curly" maintenant si vous avez rlang> = 0.4.0 .
Explication grâce à @ eipi10:
Ceci combine le processus en deux étapes de soumission puis suppression en une seule étape,
{{question}}
est donc équivalent à!!enquo(question)
Notez que contrairement à l'
ensym
approche, cela ne fonctionne pas avec les noms de personnages. Pire encore, il fait la mauvaise chose au lieu de simplement donner une erreur.la source
question
faut d'abord le transformer en une quosure (question = enquo(question)
) avant de l'utiliser dans le pipe dplyr.{{question}}
est équivalent à!!enquo(question)
.Vous pouvez rendre la fonction un peu plus flexible en permettant à un vecteur de valeurs recodées d'être également entré comme argument. Par exemple:
Notez que
recode.vec
c'est "sans guillemet" avec!!!
. Vous pouvez voir ce que cela fait avec cet exemple, adapté de la programmation avec vignette dplyr (recherchez "épissure" pour voir les exemples pertinents). Notez comment!!!
«épissure» les paires de valeurs de recodage dans larecode
fonction afin qu'elles soient utilisées comme...
argument dansrecode
.Si vous souhaitez potentiellement exécuter la fonction de recodage sur plusieurs colonnes, vous pouvez la transformer en une fonction qui ne prend qu'un nom de colonne et un vecteur de recodage. Cette approche semble être plus adaptée aux tuyaux.
Ou pour recoder une seule colonne:
la source