问题
I'm trying to learn to use ~
and .
in R.
In the code below is the same function written with and without the use of ~
and .
.I didn't understand what happened in the first function to appear the error.
#FIRST FUNCTION
col_summary2 <- function(.x, .f, ...){
.x <- purrr::keep(.x, is.numeric)
purrr::map_dbl(.x, ~.f(., ...))
}
col_summary2(mtcars,mean) #Error in mean.default(., ...) : 'trim' must be numeric of length one
#SECOND FUNCTION
col_summary2 <- function(.x, .f, ...){
.x <- purrr::keep(.x, is.numeric)
purrr::map_dbl(.x, function(x) .f(x, ...))
}
col_summary2(mtcars,mean) #mpg cyl disp hp drat wt qsec vs am gear carb
#20.090625 6.187500 230.721875 146.687500 3.596563 3.217250 17.848750 0.437500 0.406250 3.687500 2.812500
回答1:
In the first case your argument is passed to purrr::as_mapper
internally:
as_mapper(~f(., ...))
# function (..., .x = ..1, .y = ..2, . = ..1)
# f(., ...)
Which means it behaves just as if you had written :
purrr::map_dbl(.x, function(..., .x = ..1, .y = ..2, . = ..1) f(., ...))
The function that is created has a ...
argument, (it always has, it would even if .f
didn't have it).
The .x
, .y
, and .
arguments are actually extracted from the ...
, as ..1
means "first thing stuffed into ...
", ..2
means "second thing..." and so on.
So in your first case .x
is passed through ...
and ends up in .
as well.
col_summary3 <- function(.x, .f, ...){
.x <- purrr::keep(.x, is.numeric)
purrr::map_dbl(.x, ~{print(list(...));.f(., ...)})
}
col_summary3(mtcars,mean)
# [[1]]
# [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4 10.4
# [17] 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7 15.0 21.4
# Error in mean.default(., ...) : 'trim' must be numeric of length one
.x
ends up being fed both to the first argument of .f
and to the second through .f(.,...)
, so it ends up in the second argument of mean.default
, i.e. trim
, which doesn't like it.
It's not the case in your second function, where the ...
argument (not used in this case) is smoothly passed from the initial call to the .f
call.
Re "So, in this case, I can't use ~ and ., right?"
You can't use it directly as there is a conflict with ...
. You can go around it however by passing it to the .y
argument and use purr::invoke
, but that's very mean for the next person that will have to read it :).
col_summary4 <- function(.x, .f, ...){
.x <- purrr::keep(.x, is.numeric)
purrr::map_dbl(.x, ~ invoke(.f, .y, .), .y=list(...))
}
col_summary4(mtcars,mean)
# mpg cyl disp hp drat wt qsec vs am gear carb
# 20.090625 6.187500 230.721875 146.687500 3.596563 3.217250 17.848750 0.437500 0.406250 3.687500 2.812500
col_summary4(mtcars,mean, trim = 0.3)
# mpg cyl disp hp drat wt qsec vs am gear carb
# 19.1785714 6.4285714 214.5071429 136.2857143 3.5971429 3.2467857 17.7600000 0.3571429 0.2857143 3.5714286 2.6428571
来源:https://stackoverflow.com/questions/51362474/r-function-using-and