I'm new to R package development and stack overflow, but I've been unable to find this information anywhere.
I'm trying to load the R package mice, without it polluting my namespace. I've tried importing just the functions I'm using, but that hasn't worked. So I'll settle for loading the entire package in one specific environment as follows:
e <- new.env()
load_package_into_environment(e, package = "mice")
eval(mice(data, m = m, maxit = max.iter, printFlag = F), envir = e)
However, I haven't been able to find the actual function to replace the "load_package_into_environment" placeholder. What function, if any, would accomplish this?
EDIT: Here are the files I'm working with and the problem I'm having to give more detail.
File: DESCRIPTION
Package: bug.example2
Title: Example of Package Loading Bug
Version: 0.0.0.9000
Authors@R: person("R", "Woodbridge", email = "[email protected]", role = c("aut", "cre"))
Description: Creates a wrapper function for mice::mice function.
Depends:
R (>= 3.2.3),
data.table (>= 1.9.6)
License:
LazyData: true
Imports: mice
RoxygenNote: 5.0.1
File: NAMSPACE (automatically generated by roxygen)
import(data.table)
importFrom(mice,mice)
importFrom(mice,mice.impute.logreg)
importFrom(mice,mice.impute.pmm)
importFrom(mice,mice.impute.polr)
importFrom(mice,mice.impute.polyreg)
File: impute.R (uses the mice function from the mice package)
#' @import data.table
#' @importFrom mice mice
#' @importFrom mice mice.impute.pmm
#' @importFrom mice mice.impute.logreg
#' @importFrom mice mice.impute.polyreg
#' @importFrom mice mice.impute.polr
#' @export
impute <- function(data, m = 5, max.iter = 5){
mice_environment <- new.env()
#Impute missing data using mice function, output format is mids object
mice.out <- mice(data, m = m, maxit = max.iter, printFlag = F)
#save the m imputed data.frames as a list of data.tables
return.list <- lapply(1:m, function(x){
as.data.table(complete(mice.out, x))
})
names(return.list) <- paste0("imp.",1:m)
return.list
}
File: test-impute.R (uses testthat package to test impute function)
context("Impute missing values")
test_that("Output format is a list of lenght m and each element is a data.table",{
#Set up data
set.seed(200)
data <- iris
data$Species[runif(nrow(data)) < .1] <- NA
data$Sepal.Width[runif(nrow(data)) < .2] <- NA
setDT(data)
#Create imputed data
M <- 5
impute.output <- impute(data, m = M)
#Test output format
expect_is(impute.output, "list")
expect_equal(length(impute.output), M)
lapply(impute.output,expect_is, "data.table")
})
Error output from testthat
1. Error: Output format is a list of lenght m and each element is a data.table -
The following functions were not found: mice.impute.pmm, mice.impute.polyreg
1: withCallingHandlers(eval(code, new_test_environment), error = capture_calls, message = function(c) invokeRestart("muffleMessage"))
2: eval(code, new_test_environment)
3: eval(expr, envir, enclos)
4: impute(data, m = M) at test-impute.R:12
5: mice(data, m = m, maxit = max.iter, printFlag = F) at C:\repos\bug.example2/R/impute.R:11
6: check.method(setup, data)
7: stop(paste("The following functions were not found:", paste(fullNames[notFound],
collapse = ", ")))
Package 'mice' internally is calling imputations methods from the global environment. According to the authors this is to allow providing your own, custom methods for imputations. As such, the package must expose their default implementations in the global environment as well. I recon this is a nice example of pure judgement - internal methods are now recognized by the package only through the global environment. This is defeating the purpose of packaging code in the first place. If one wants to allow external functions to be used by your package, then simply provide an API for passing them to the package.
The error message you see is triggered by function 'mice:::check_method':
notFound <- !vapply(fullNames, exists, logical(1), mode = "function", inherits = TRUE)
My workaround is to re-export methods used internally by 'mice' from my own package (which internally uses 'mice', just like yours). Simply put in one of your R files and run roxygen2 on it:
#' @importFrom mice mice
#' @export
mice.impute.pmm <- mice::mice.impute.pmm
#' @export
mice.impute.polyreg <- mice::mice.impute.polyreg
Of course you'll need to export other methods if they are used on your data.
My stand point is that if I need to pollute the global environment, I'll pollute it minimally, only with functions required for 'mice' to work.
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