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.Widthvariable:
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?

dplyrtiene 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
mutatefunció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
dplyrque existían cuando la pregunta se planteó originalmente. Requiere un uso cuidadoso dequoteysetName: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.callanterior para usardo.call("mutate")y citardfen la lista. ¿Es eso lo que estabas sugiriendo? Y cuando lalazyevalversión dedplyres 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.0en 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
multipetalaplicado 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
dplyrfunciones. Aquí estáfilter:O
arrange:Para
select, no necesita usar el patrón. En su lugar, puede usar!!:fuente
myCola una url (por ejemplo) y copio la columna anteriormyColInitialValueal final del marco de datosdfcon 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 elescapeparámetro deDT::datatable(). Yo usoescape=FALSEen esperar eso. Con las constantes no funciona también, pero el paquete DT también parece tener la columna # incorrecta. :)escapeunDT::datatablevarname = 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.0tenemos 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.dotsargumento. 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
dplyrmucho en configuraciones no interactivas, usarlo con entrada variable dentro de una función usa una sintaxis muy torpe.Puede disfrutar de un paquete
friendlyevalque presenta una API de evaluación ordenada simplificada y documentación para nuevos / casualesdplyrusuarios .Está creando cadenas que desea
mutatetratar como nombres de columna. Entonces, usandofriendlyevalpodría escribir:Que bajo el capó llama
rlangfunciones que compruebanvarnamees legal como nombre de columna.friendlyevalel 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.0pero no estoy seguro (también tengorlang 4.7.0si importa).fuente