I want to apply a series of dplyr-verbs
; and for my example specifically, I am interested in mutate
. Essentially, I want to produce an output that would look like this:
mtcars %>% mutate(x1=1) %>% mutate(x2=2) %>% mutate(x3=3) ...
Essentially, I have tried:
anotherTest <- function(data,...){
cols = list(...)
testFunc <- function(more){
return(mutate(x = more))
}
n <- length(cols)
addMutation <- replicate(n, testFunc)
test <- {{data}} %>% lapply(addMutation, function(x){ x(cols)})
return(test)
}
anotherTest(mtcars, 1)
But this produces the following error:
Error in get(as.character(FUN), mode = "function", envir = envir) : object 'addMutation' of mode 'function' was not found
Here is what I am trying to get - I am more interested in the logic than getting the naming output with mutate
, because we are aiming for a series of dplyr-verbs:
anotherTest <- function(data,...){
cols = enquos(...)
testFunc <- function(more){
return(mutate(x = !!!more))
}
n <- length(cols)
addMutation <- replicate(n, testFunc)
addCars <- replicate(n, data)
mapply(function(x, y, z)y %>% x(z), addMutation, addCars, cols)
}
anotherTest(mtcars, vs, gear)
However, I get this:
Error in x(., z) : unused argument (z)
Whereas if I do not add an argument, I get this error:
Error in UseMethod("mutate") : no applicable method for 'mutate' applied to an object of class "logical"
Which makes sense as no value as been added for mutate
however, adding a value strangely causes an error.
Additionaly example where what I am after can be very useful to understand. If I wanted to created a series of nested lists then I could generalise likeso:
nestLoop <- function(data, main, sub = NULL, ...) {
cols <- enquos(...)
outerNest <- data %>% nest_by({{main}})
repeatNest <- function(cols) {
return(mutate(data = map(data, ~ .x %>% nest(data = -{{!!!cols}}))))
}
for (num in seq_along(cols)) {
nested <-
outerNest %>% ungroup %>% mutate(data = map(data, ~ .x %>% nest(data = -{{sub}}) %>% repeatNest(cols[num])))
}
nested
}
nestLoop(mtcars, vs, am, gear)
However, this creates the following error:
Error in
mutate()
: ! Problem while computingdata = map(data, ~.x %>% nest(data = -am) %>% repeatNest(cols[num]))
. Caused by error inrepeatNest()
: ! unused argument (cols[num])
As you can see from this example the following logic for %>% mutate(x1=1) %>% mutate(x2=2) %>% mutate(x3=3)
would have to be exact, otherwise the lists will not nest sequentially.
CodePudding user response:
func <- function(x, ...) {
dots <- list(...)
for (ind in seq_along(dots)) {
nm <- paste0("x", ind)
x <- mutate(x, {{nm}} := dots[[ind]])
}
x
}
func(head(mtcars, 3), 1, 3)
# mpg cyl disp hp drat wt qsec vs am gear carb x1 x2
# Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 1 3
# Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 1 3
# Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 1 3
Another option:
func <- function(...) {
dots <- list(...)
data.frame(
setNames(dots, paste0("x", seq_along(dots)))
)
}
head(mtcars, 3) %>%
mutate(func(1, 3))
# mpg cyl disp hp drat wt qsec vs am gear carb x1 x2
# Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 1 3
# Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 1 3
# Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 1 3
CodePudding user response:
1) Cut down mtcars to make the output shorter. Now, mutate
can take a data.frame as an argument so create a one row data.frame with the desired names and values and pass it to mutate
.
library(dplyr)
n <- 3
mtcars %>%
select(1:4) %>%
head(4) %>%
mutate(setNames(data.frame(as.list(1:n)), tolower(make.names(1:n))))
giving:
mpg cyl disp hp x1 x2 x3
Mazda RX4 21.0 6 160 110 1 2 3
Mazda RX4 Wag 21.0 6 160 110 1 2 3
Datsun 710 22.8 4 108 93 1 2 3
Hornet 4 Drive 21.4 6 258 110 1 2 3
2) cbind mtcars and a list of data.frames.
cbind(mtcars[1:4, 1:4],
list(data.frame(x1 = 1), data.frame(x2 = 2), data.frame(x3 = 3)))
3) create a chain of mutates (the result is a function) and use it with mtcars.
chain <- . %>% mutate(x1 = 1) %>% mutate(x2 = 2) %>% mutate(x3 = 3)
mtcars[1:4, 1:4] %>% chain