The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

inspector: Validation of Arguments and Objects in User-Defined Functions

CRAN status Build Status R build status pkgdown codecov License: MIT

Overview

The inspector package provides utility functions that implement and automate common sets of validation tasks, namely:

These functions are particularly useful to validate inputs, intermediate objects and output values in user-defined functions, resulting in tidier and less verbose functions.

Installation

The development version of inspector can be installed from Github with the devtools package:

# install.packages("devtools")
devtools::install_github("ptfonseca/inspector")

Usage

Imagine we want to write a function that simulates n flips of the same coin. Assuming that bias is the probability of the “heads” outcome:

set.seed(123)

flip_coins <- function(n, bias) { 
  
  sample(x = c("heads", "tails"), size = n, replace = TRUE)
}

flip_coins(n = 5, bias = 0.5)
#> [1] "heads" "heads" "heads" "tails" "heads"

Since bias is a probability, it is natural that we require flip_coins() to only accept values of bias between 0 and 1. Furthermore, we may want to ensure that bias is not null, not missing, and is a numeric vector of length 1. This results an a quite verbose function body:

set.seed(123)

flip_coins <- function(n, bias) {
  
  if (is.null(bias)) {
    stop(paste("Invalid argument: bias is NULL."))
  }
  if (any(isFALSE(is.atomic(bias)), isFALSE(is.vector(bias)))) {
    stop(paste("Invalid argument: bias must be an atomic vector."))
  }
  if (isFALSE(length(bias) == 1)) {
    stop(paste("Invalid argument: bias must be of length 1."))
  }
  if (is.na(bias)) {
    stop(paste("Invalid argument: bias is NA or NaN."))
  }
  if (isFALSE(is.numeric(bias))) {
    stop(paste("Invalid argument: bias must be numeric."))
  }
  if (any(bias >= 1, bias <= 0)) {
    stop(paste("Invalid argument: bias must be in the (0, 1) interval."))
  }
  
  sample(x = c("heads", "tails"), size = n, replace = TRUE)
}

flip_coins(n = 5, bias = 0.5)
#> [1] "heads" "heads" "heads" "tails" "heads"

The inspector package was built to automate this kind of validation task. In the flip_coins() example, to perform an equivalent validation of inputs we can use inspect_par_bernoulli, since bias is the parameter of a Bernoulli distribution:

set.seed(123)

flip_coins <- function(n, bias) {
  
  inspect_par_bernoulli(bias)
  
  sample(x = c("heads", "tails"), size = n, replace = TRUE)
}

flip_coins(n = 5, bias = 0.5)
#> [1] "heads" "heads" "heads" "tails" "heads"

This results in a tidier function body since the validation of bias is abstracted away from the body of the function.

Now imagine we want to implement equation 4 from Berger and Delampady (1987), a formula that calculates posterior probabilities using prior probabilities and Bayes factors as input. In this case we need to validate a vector of Bayes factors, lets call it bf, and a vector of prior probabilities, lets call it prior_prob. Since bf is expected to contain valid Bayes factor values, we need to ensure that only non-empty numeric vectors, containing only non-negative values, are accepted. Since prior_prob is a vector of probabilities, we need to check if it is a non-empty numeric vector containing only values between 0 and 1. Since we are now validating two inputs, the function body would be even more verbose than in the flip_coins() example:

bfactor_to_prob <- function(bf, prior_prob = .5) {

  if (is.null(bf)) {
    stop(paste("Invalid argument: bf is NULL."))
  }
  if (any(isFALSE(is.atomic(bf)), isFALSE(is.vector(bf)))) {
    stop(paste("Invalid argument: bf must be an atomic vector."))
  }
  if (length(bf) == 0) {
    stop(paste("Invalid argument: bf is empty."))
  }
  if (all(is.na(bf))) {
    stop(paste("Invalid argument: all elements of bf are NA or NaN."))
  }
  if (isFALSE(is.numeric(bf))) {
    stop(paste("Invalid argument: the type of bf must be numeric."))
  }
  if (any(bf[!is.na(bf)] < 0)) {
    stop(paste("Invalid argument: all elements of bf must be non-negative."))
  }
  if (is.null(prior_prob)) {
    stop(paste("Invalid argument:", output_name, "is NULL."))
  }
  if (any(isFALSE(is.atomic(prior_prob)), isFALSE(is.vector(prior_prob)))) {
    stop(paste("Invalid argument:", output_name, "must be an atomic vector."))
  }
  if (length(prior_prob) == 0) {
    stop(paste("Invalid argument:", output_name, "is empty."))
  }
  if (all(is.na(prior_prob))) {
    stop(paste("Invalid argument: all elements of", output_name, "are NA or NaN."))
  }
  if (isFALSE(is.numeric(prior_prob))) {
    stop(paste("Invalid argument: the type of", output_name, "must be numeric."))
  }
  if (any(prior_prob[!is.na(prior_prob)] < 0, prior_prob[!is.na(prior_prob)] > 1)) {
    stop(paste("Invalid argument: all elements of",  output_name, "must be in the [0, 1] interval."))
  }

  (1 + (1 - prior_prob) / prior_prob * (1 / bf)) ^(-1)
}

bfactor_to_prob(c(2.1, 0.5, 11))
#> [1] 0.6774194 0.3333333 0.9166667

Now lets use inspector instead. To perform an equivalent validation of inputs we can use inspect_bfactor() to validate bf and inspect_prob() to validate prior_prob:

bfactor_to_prob <- function(bf, prior_prob = .5) {

  inspect_bfactor(bf)
  inspect_prob(prior_prob)

  (1 + (1 - prior_prob) / prior_prob * (1 / bf)) ^ (-1)
}

bfactor_to_prob(c(2.1, 0.5, 11))
#> [1] 0.6774194 0.3333333 0.9166667

Getting Help

If you find a bug, please file an issue with a minimal reproducible example on GitHub. Feature requests are also welcome. You can find me at ptfonseca@iseg.ulisboa.pt.

References

Berger, James O., and Mohan Delampady. 1987. “Testing Precise Hypotheses.” Statistical Science 2 (3): 317–35.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.