Considere uma tag em que cada coluna é um vetor de caracteres que pode assumir muitos valores - digamos "A" a "F".
library(tidyverse)
sample_df <- tibble(q1 = c("A", "B", "C"), q2 = c("B", "B", "A"))
Desejo criar uma função que tome o nome de uma coluna como argumento e recodifique essa coluna para que qualquer resposta "A" se torne um NA e o df seja retornado como está. O motivo para projetá-lo dessa maneira é se encaixar em um pipeline mais amplo que executa uma série de operações usando uma determinada coluna.
Existem diversas formas de fazer isto. Mas estou interessado em entender qual seria a melhor abordagem idiomática tidy_eval / tidyverse. Primeiro, o nome da pergunta precisa estar no lado esquerdo de um verbo mutado; portanto, usamos os operadores !!
e :=
adequadamente. Mas então, o que colocar no lado direito?
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")
Meu pensamento inicial era que isso funcionaria:
df %>% mutate(!!question := recode(!!question, "A" = NA_character_))
Mas é claro que o bang-bang dentro da função apenas retorna a cadeia de caracteres literal (por exemplo, "q1"). Acabei pegando o que parece uma rota hacky para referenciar os dados no lado direito, usando o [[
operador R base e confiando na .
construção do dplyr, e funciona, então, em certo sentido, resolvi meu problema subjacente:
df %>% mutate(!!question := recode(.[[question]], "A" = NA_character_))
Estou interessado em receber feedback de pessoas que são muito boas em termos de arrumação quanto à existência de uma maneira mais idiomática de fazer isso, na esperança de que ver um exemplo funcionado melhore minha compreensão da função arrumada de maneira mais geral. Alguma ideia?
q1
(símbolo) e"q1"
(string):df %>% mutate_at( vars(!!ensym(question)), recode, A = NA_character_)
Respostas:
Aqui, no lado direito
:=
, podemos especificarsym
para converter em símbolo e depois avaliar (!!
)Uma abordagem melhor que funcionaria para as entradas citadas e não citadas é
ensym
fonte
Você pode usar o método "curly curly" agora se tiver rlang> = 0.4.0 .
Explicação graças a @ eipi10:
Isso combina o processo de duas etapas de cotação e cotação em uma etapa, portanto,
{{question}}
é equivalente a!!enquo(question)
Observe que, diferentemente da
ensym
abordagem, isso não funciona com nomes de personagens. Pior ainda, faz a coisa errada, em vez de apenas dar um erro.fonte
question
primeiro precisa ser transformado em um quosure (question = enquo(question)
) antes de ser usado no dplyr pipe.{{question}}
é equivalente a!!enquo(question)
.Você pode tornar a função um pouco mais flexível, permitindo que um vetor de valores recodificados também seja inserido como argumento. Por exemplo:
Observe que
recode.vec
é "sem aspas" com!!!
. Você pode ver o que isso está fazendo neste exemplo, adaptado da vinheta Programação com dplyr (procure por "emenda" para ver os exemplos relevantes). Note como!!!
"emendas" os pares de recodificação valores para arecode
função de modo que eles são usados como...
argumento emrecode
.Se você deseja executar potencialmente a função de recodificação em várias colunas, pode transformá-la em uma função que leva apenas um nome de coluna e um vetor de recodificação. Essa abordagem parece que seria mais fácil de usar.
Ou para recodificar uma única coluna:
fonte