I want to write a function that applies one of two different statistical methods to its input. In the process, I noticed some behavior of different functions that I do not understand. The function I want to write should have the following properties:
Basically, I want the function to behave like cor
does in R. There, you have a default value method = c("pearson", "kendall", "spearman")
, and the functions calculated the Pearson correlation if method
isn't specified. If the user asks for several methods at once, the function returns an error.
From looking at cor
, this appears to be done using match.arg(method)
. This behavior is illustrated here:
x <- y <- 1:5
cor(x, y, method="pearson")
# = 1
cor(x, y, method="kendall")
# = 1
cor(x, y, method=c("pearson","kendall"))
# gives an error
I tried writing my own function, also using match.arg(method)
, but I realized that the result is somehow different.
Even when choosing a vector for method
, the function doesn't terminate with an error, but returns the results of the first method.
This is illustrated here:
myfun <- function(x, method=c("add","multiply")){
method <- match.arg(method)
if(method=="add") return(sum(x))
if(method=="multiply") return(prod(x))
}
x <- 1:5
myfun(x, method="add")
# = 15
myfun(x, method="multiply")
# = 120
myfun(x, method=c("add","multiply"))
# = 15
I don't understand this behavior, and I would be glad if you could help me out here. From my attempts on Google, I realize that it might be related to non-standard evaluation, but I can't put two and two together just yet.
Thanks in advance, your help is much appreciated!
Cheers!
EDIT:
I could also re-phrase my question:
What powerful sorcery does cor
do that it returns the Pearson correlation when method
is not supplied, but that it returns an error when method = c("pearson", "kendall", "spearman")
is explicitly specified?
If choices
and args
are the same in match.arg
, then the first element is returned. Otherwise arg
has to be length 1. From match.arg
:
Since default argument matching will set arg to choices, this is allowed as an exception to the ‘length one unless several.ok is TRUE’ rule, and returns the first element.
match.arg(c("pearson", "kendall", "spearman"), c("pearson", "kendall", "spearman"))
## [1] "pearson"
match.arg(c("pearson", "kendall"), c("pearson", "kendall", "spearman"))
## Error in match.arg(c("pearson", "kendall"), c("pearson", "kendall", "spearman")) :
## 'arg' must be of length 1
You can get your desired behavior using a dummy argument:
myfun <- function(x, method=c("add","multiply","other.return.error")){
method <- match.arg(method)
if("other.return.error" %in% method) stop("this option should not be used")
if(method=="add") return(sum(x))
if(method=="multiply") return(prod(x))
}
The main question was answered by @shadow (see above).
Another way of getting the desired behavior for myfun
is to perform a check if method
is supplied or not and printing an error if it was explicitly supplied with more than one element.
myfun <- function(x, method=c("add","multiply")){
if(!missing(method) & length(method)>1) stop("Only one 'method' allowed.")
method <- match.arg(method)
if(method=="add") return(sum(x))
if(method=="multiply") return(prod(x))
}
x <- 1:5
myfun(x)
# = 15
myfun(x, method="add")
# = 15
myfun(x, method="multiply")
# = 120
myfun(x, method=c("add","multiply"))
# gives error
This circumvents the exception in match.arg
pointed out by @shadow by which supplying a vector to the function may not cause an error.
Instead, this error is given right away.
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