5

I'm working on a custom R package (it is private, not hosted anywhere). In this package, I have a function that takes xgboost, RandomForest (from the ranger function), and glmnet models and uses them to predict on a new dataset.

Each time I'm predicting, I use the same generalized predict function. If I don't namespace the function, R doesn't know which library to use for the predict.

The error I get is:

Error in UseMethod("predict") : 
  no applicable method for 'predict' applied to an object of class "c('lognet', 'glmnet')" 

If I load the functions manually, it works, but I know that loading packages manually within an R library is a taboo.

I tried using glmnet::glmnet.predict, etc. but this is giving me errors, as well. What would be the proper way to namespace these predict functions to avoid loading the libraries manually?

matsuo_basho
  • 2,833
  • 8
  • 26
  • 47
  • 2
    I would have thought that merely Import-ing the packages (or the relevant parts of them) would be sufficient (although I would still prefix the calls for clarity). Have you tried that? Also, you say you get "errors" but you don't say what they are. That would be very helpful information for anyone trying to help you. – joran Sep 26 '18 at 22:25
  • I get the same message for all three of those packages: "No documentation for ‘predict’ in specified packages and libraries: you could try ‘??predict’" Shouldn't you be using the DESCRIPTION file to "Import"? Once the packages are referenced they (or specific functions from them) get put on the search path. so appropriately tailored functions can be dispatched based on the class or classes of the arguments. – IRTFM Sep 26 '18 at 22:31
  • Look at `package:caret` for examples. – IRTFM Sep 26 '18 at 22:37
  • The predict function is predict.{library name}. Ex. predict.glmnet https://cran.r-project.org/web/packages/glmnet/glmnet.pdf – matsuo_basho Sep 26 '18 at 22:37
  • It should actually be predict.{class name}. Look at `help(pack=xgboost)`. There is no `predict.xgboost`. – IRTFM Sep 26 '18 at 22:40
  • 1
    Is this a duplicate? https://stackoverflow.com/questions/30778718/how-to-use-s3-methods-from-another-package-which-uses-export-rather-than-s3metho – IRTFM Sep 26 '18 at 22:43
  • @joran, what exactly do you mean by importing the packages? I have the custom library as an RStudio project. I am rebuilding the package. The relevant libraries are in the imports row of the DESCRIPTION file – matsuo_basho Sep 26 '18 at 22:44
  • Look at the generated NAMESPACE file to see whether it has import directives for those packages. If not, that's likely the problem. Some people write the NAMESPACE files themselves, but I typically have it built automatically based on documentation directives from roxygen2. – joran Sep 26 '18 at 22:50
  • 42, the question is worded a bit differently, but it appears it is referring to the same thing. Adding `@importFrom glmnet predict` and analogous ones for the other 2 libraries seems to have done the trick. Up to the community to decide whether my question is a pure duplicate – matsuo_basho Sep 26 '18 at 23:55
  • Hmm, it seemed to have worked before, but when I re-built the package, I got an error: `Error : object ‘predict’ is not exported by 'namespace:glmnet'` – matsuo_basho Sep 27 '18 at 00:05
  • The package author may not have written the NAMESPACE configuration properly. Does it work if you import `predict.glmnet`? I see that function name in the list of `methods(predict)` after loading the package but I still get "No documentation for ‘predict’ in specified packages and libraries:" after running: `help(predict, pac=glmnet)` – IRTFM Sep 27 '18 at 01:28
  • The package rebuilds if I substitute with `predict.glmnet`, `predict.ranger`, `predict.xgb.Booster`. The imports appear in NAMESPACE if I do devtools::document() and I am then able to run the function in question that calls predict by all 3 algorithms. However, what is weird is that after this, if I rebuild the package, I get the same error `Error : object ‘predict.ranger’ is not exported by 'namespace:ranger'`. This is interesting, because ranger appears after glmnet in the namespace, so it seems glmnet doesn't seem to be throwing the error. – matsuo_basho Sep 27 '18 at 10:57
  • Is your package on github perhaps so we can see and ideally reproduce your problem? – cdeterman Sep 28 '18 at 16:38
  • @cdeterman, no unfortunately this is a proprietary package – matsuo_basho Sep 28 '18 at 23:41
  • @matsuo_basho perhaps you can make a smaller one that reproduces the problem? Otherwise I don't know how much more help we can provide here. – cdeterman Oct 01 '18 at 16:08

1 Answers1

1

I've run into this myself on occasion where, for example, this works:

ranger::predictions(predict(model, data))

but this does not, under identical circumstances:

predict(model, data)

Your package presumably Imports the necessary dependency, but the various S3 methods, including predict.<class>(), are never registered for use unless you tell R to use them at some point earlier in your program. You can fix this by adding requireNamespace(<package name>, quietly = TRUE) either at the top of the given function or in .onLoad(). This causes R to register the appropriate S3 methods, etc., and you can confirm this by checking methods(predict) before and after. Importantly, this is true for non-exported methods that disallow roxygen2 declarations like #' @importFrom <package name> <predict.class>.

In my particular example above, :: causes R to load ranger along with its various S3 methods, including predict.ranger(), so predict() dispatches just fine.

tomshafer
  • 795
  • 3
  • 8
  • 12