Quiero usar dplyr::mutate()
para crear múltiples columnas nuevas en un marco de datos. Los nombres de columna y sus contenidos deben generarse dinámicamente.
Datos de ejemplo de iris:
library(dplyr)
iris <- tbl_df(iris)
He creado una función para mutar mis nuevas columnas de la Petal.Width
variable:
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
df <- mutate(df, varname = Petal.Width * n) ## problem arises here
df
}
Ahora creo un bucle para construir mis columnas:
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
Sin embargo, dado que mutate piensa que varname es un nombre de variable literal, el ciclo solo crea una nueva variable (llamada varname) en lugar de cuatro (llamada petal.2 - petal.5).
¿Cómo puedo mutate()
usar mi nombre dinámico como nombre de variable?
dplyr
tiene una viñeta completa sobre evaluación no estándarmutate_
, y realmente no es obvio por las otras funciones cómo usarla.Respuestas:
Dado que está construyendo dinámicamente un nombre de variable como un valor de carácter, tiene más sentido hacer la asignación utilizando la indexación de data.frame estándar que permite valores de caracteres para los nombres de columna. Por ejemplo:
La
mutate
función hace que sea muy fácil nombrar nuevas columnas a través de parámetros con nombre. Pero eso supone que conoce el nombre cuando escribe el comando. Si desea especificar dinámicamente el nombre de la columna, también debe crear el argumento con nombre.versión dplyr> = 0.7
La última versión de
dplyr
(0.7) hace esto usando:=
para asignar dinámicamente nombres de parámetros. Puedes escribir tu función como:Para obtener más información, consulte el formulario de documentación disponible
vignette("programming", "dplyr")
.dplyr (> = 0.3 y <0.7)
La versión ligeramente anterior de
dplyr
(> = 0.3 <0.7), fomentó el uso de alternativas de "evaluación estándar" para muchas de las funciones. Consulte la viñeta de evaluación no estándar para obtener más información (vignette("nse")
).Entonces, la respuesta es usar en
mutate_()
lugar demutate()
y hacer:dplyr <0.3
Tenga en cuenta que esto también es posible en versiones anteriores de las
dplyr
que existían cuando la pregunta se planteó originalmente. Requiere un uso cuidadoso dequote
ysetName
:fuente
do.call()
probablemente no hace lo que crees que hace: rpubs.com/hadley/do-call2 . Vea también la viñeta nse en la versión de desarrollo de dplyr.do.call
anterior para usardo.call("mutate")
y citardf
en la lista. ¿Es eso lo que estabas sugiriendo? Y cuando lalazyeval
versión dedplyr
es la versión lanzada,mutate_(df, .dots= setNames(list(~Petal.Width * n), varname))
¿sería una mejor solución?mutate(df, !!newVar := (!!var1 + !!var2) / 2)
, no funciona :(En la nueva versión de
dplyr
(0.6.0
en espera de abril de 2017), también podemos hacer una asignación (:=
) y pasar variables como nombres de columna quitando las comillas (!!
) para no evaluarloComprobación de la salida basada en @ MrFlick's
multipetal
aplicado en 'iris1'fuente
Después de muchas pruebas y errores, el patrón me pareció
UQ(rlang::sym("some string here")))
realmente útil para trabajar con cadenas y verbos dplyr. Parece funcionar en muchas situaciones sorprendentes.Aquí hay un ejemplo con
mutate
. Queremos crear una función que agregue dos columnas, donde pase la función de ambos nombres de columna como cadenas. Podemos usar este patrón, junto con el operador de asignación:=
, para hacer esto.El patrón también funciona con otras
dplyr
funciones. Aquí estáfilter
:O
arrange
:Para
select
, no necesita usar el patrón. En su lugar, puede usar!!
:fuente
myCol
a una url (por ejemplo) y copio la columna anteriormyColInitialValue
al final del marco de datosdf
con un nuevo nombre. Pero unwhich(colnames(df)=='myCol')
envío de vuelta el col # demyColInitialValue
. Todavía no escribí un problema porque no encontré una reprex. Mi objetivo es para elescape
parámetro deDT::datatable()
. Yo usoescape=FALSE
en esperar eso. Con las constantes no funciona también, pero el paquete DT también parece tener la columna # incorrecta. :)escape
unDT::datatable
varname = sym("Petal.Width"); ggplot(iris, aes(x=!!varname)) + geom_histogram()
Aquí hay otra versión, y podría decirse que es un poco más simple.
fuente
Con
rlang 0.4.0
tenemos operadores rizado-rizado ({{}}
) lo que hace que esto sea muy fácil.También podemos pasar nombres de variables entre comillas / sin comillas que se asignarán como nombres de columna.
Funciona igual con
fuente
También estoy agregando una respuesta que aumenta esto un poco porque llegué a esta entrada cuando buscaba una respuesta, y esto tenía casi lo que necesitaba, pero necesitaba un poco más, que obtuve a través de la respuesta de @MrFlik y el R lazyeval viñetas.
Quería hacer una función que pudiera tomar un marco de datos y un vector de nombres de columna (como cadenas) que quiero convertir de una cadena a un objeto Date. No pude encontrar la forma de
as.Date()
tomar un argumento que es una cadena y convertirlo en una columna, así que lo hice como se muestra a continuación.A continuación se muestra cómo hice esto a través de SE mutate (
mutate_()
) y el.dots
argumento. Las críticas que lo mejoran son bienvenidas.fuente
Si bien disfruto usando dplyr para uso interactivo, me resulta extraordinariamente complicado hacerlo usando dplyr porque tienes que pasar por aros para usar lazyeval :: interp (), setNames, etc.
Aquí hay una versión más simple que usa la base R, en la que me parece más intuitivo, al menos para mí, poner el bucle dentro de la función, y que extiende la solución de @ MrFlicks.
fuente
dplyr
mucho en configuraciones no interactivas, usarlo con entrada variable dentro de una función usa una sintaxis muy torpe.Puede disfrutar de un paquete
friendlyeval
que presenta una API de evaluación ordenada simplificada y documentación para nuevos / casualesdplyr
usuarios .Está creando cadenas que desea
mutate
tratar como nombres de columna. Entonces, usandofriendlyeval
podría escribir:Que bajo el capó llama
rlang
funciones que compruebanvarname
es legal como nombre de columna.friendlyeval
el código se puede convertir a un código de evaluación simple y ordenado equivalente en cualquier momento con un complemento RStudio.fuente
Otra alternativa: use
{}
comillas internas para crear fácilmente nombres dinámicos. Esto es similar a otras soluciones, pero no exactamente lo mismo, y me resulta más fácil.Creo que esto proviene,
dplyr 1.0.0
pero no estoy seguro (también tengorlang 4.7.0
si importa).fuente