I'm using the 'caret' library to to do some cross validation on some trees.
The library provides a function called train
, that takes in a named argument "method". Via its ellipsis it's supposed to let other arguments fall through to another function that it calls. This other function (rpart
) takes an argument of the same name, "method".
Therefore I want to pass two arguments with the same name... and it's clearly failing. I tried to work around things as shown below but I get the error:
"Error in train.default(x = myx, y = myy, method = "rpart2", preProcess = NULL, : formal argument "method" matched by multiple actual arguments"
any help is much appreciated! thanks!
train.wrapper = function(myx, myy, mytrControl, mytuneLenght, ...){
result = train(
x=myx,
y=myy,
method="rpart2",
preProcess=NULL,
...,
weights=NULL,
metric="Accuracy",
trControl=mytrControl,
tuneLength=mytuneLenght
)
return (result)
}
dtree.train.cv = train.wrapper(training.matrix[,2:1777],
training.matrix[,1],
2, method="class")
This name is used within the method body to refer to the passed-in argument. The name of a parameter must be unique in its scope. It cannot be the same as the name of another parameter for the same method or constructor, and it cannot be the name of a local variable within the method or constructor.
If that means that the names should be the same, so be it. If that means that they should be different, so be it. All depends on what is most accurate and clear in the given program.
When you pass an argument by name, you specify the argument's declared name followed by a colon and an equal sign ( := ), followed by the argument value. You can supply named arguments in any order. When you call this procedure, you can supply the arguments by position, by name, or by using a mixture of both.
Using named parameters in C#, we can put any parameter in any sequence as long as the name is there. The right parameter value based on their names will be mapped to the right variable. The parameters name must match with the method definition parameter names.
Here's a mock-up of your problem with a tr
(train) function that calls an rp
(rpart) function, passing it ...
:
rp <- function(method, ...) method
tr <- function(method, ...) rp(...)
# we want to pass 2 to rp:
tr(method=1, method=2) # Error
tr(1, method=2) # 1, (wrong value!)
tr(method=1, metho=2) # 2 (Yay!)
What magic is this? And why does the last case actually work?! Well, we need to understand how argument matching works in R. A function f <- function(foo, bar)
is said to have formal parameters "foo" and "bar", and the call f(foo=3, ba=13)
is said to have (actual) arguments "foo" and "ba".
R first matches all arguments that have exactly the same name as a formal parameter. This is why the first "method" argument gets passed to train
. Two identical argument names cause an error.
Then, R matches any argument names that partially matches a (yet unmatched) formal parameter. But if two argument names partially match the same formal parameter, that also causes an error. Also, it only matches formal parameters before ...
. So formal parameters after ...
must be specified using their full names.
Then the unnamed arguments are matched in positional order to the remaining formal arguments.
Finally, if the formal arguments include ...
, the remaining arguments are put into the ...
.
PHEW! So in this case, the call to tr
fully matches method
, and then pass the rest into ...
. When tr
then calls rp
, the metho
argument partially matches its formal parameter method
, and all is well!
...Still, I'd try to contact the author of train
and point out this problem so he can fix it properly! Since "rpart" and "rpart2" are supposed to be supported, he must have missed this use case!
I think he should rename his method
parameter to method.
or similar (anything longer than "method"). This will still be backward compatible, but allows another method
parameter to be passed correctly to rpart
.
Generally wrappers will pass their parameters in a named list. In the case of train
, provision for control is passed in the trControl argument. Perhaps you should try:
dtree.train.cv = train.wrapper(training.matrix[,2:1777],
training.matrix[,1],
2, # will be positionally matched, probably to 'myTuneLenght'
myTrControl=list(method="class") )
After your comment I reviewed again the train
and rpart
help pages. You could well be correct in thinking that trControl has a different purpose. I am suspicious that you may need to construct your call with a formula since rpart
only has a formula method. If the y argument is a factor than method="class will be assumed by rpart
. And ... running modelLookup:
modelLookup("rpart2")
model parameter label seq forReg forClass probModel
154 rpart2 maxdepth Max Tree Depth TRUE TRUE TRUE TRUE
... suggest to me that a "class" method would be assumed by default as well. You may also need to edit your question to include a data example (perhaps from the rpart
help page?) if you want further advice.
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