I would like to apply a function to a vector. However, the function is expecting a sequence of arguments. Thus, I need to "split" the vector into unrelated arguments.
Suppose that I have a dataframe called dta. I want to run a function, say mean on one of its column, say DV.
The following shows the problem
call("mean", dta$DV)
returns
mean(c(0.371, -0.860, etc... ))
The fact that the column is a vector is not compatible with the function mean which expects a sequence of arguments, not combined.
The solution should work if "mean" is replaced by a variable containing a string, e.g.
fun <- "mean"
call( fun, dta$DV)
R has functions that are not completely consistent. For instance, min
and max
accept arbitrary numbers of arguments, where all unrecognized arguments are considered in the mathematical calculation. mean
is not, it must have all numbers to be considered as the first (or named x=
) argument.
min(1,20,0)
# [1] 0
min(c(1,20,0))
# [1] 0
mean(1,20,0) # might not be what one would expect
# [1] 1
mean(c(1,20,0))
# [1] 7
For the curious, the 20 and 0 are not ignored, the first mean
call is interpreted as mean(0, trim=20, na.rm=0)
(where na.rm=0
is effectively the same as na.rm=FALSE
).
Your use of call
is a little off. From the help ?call
,
call returns an unevaluated function call
which doesn't really help you a lot. You might do eval(call(...))
, but that seems silly in light of this next function.
Use of do.call
is a bit more straight forward. I can take as its first argument: a function (anonymous or named) or a character string which matches a function. There are actually speed differences between using one or the other, so I tend to use a character
reference to the function name when able. (I don't recall the reference that quantifies this assertion, I'll include it if I find it soon.)
For functions like min
above that can accept any number of arguments, one can do this:
args <- c(1,20,0)
as.list(args)
# [[1]]
# [1] 1
# [[2]]
# [1] 20
# [[3]]
# [1] 0
do.call("min", as.list(args)) # == min(1,20,0)
# [1] 0
list(args)
# [[1]]
# [1] 1 20 0
do.call("min", list(args)) # == min(c(1,20,0))
# [1] 0
However, for mean
and similar, you need to force the latter behavior:
do.call("mean", list(args)) # == mean(c(1,20,0))
# [1] 7
For you to call a function with programmatically-defined arguments, you need to use do.call
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With