MyNixOS website logo
Description

Validation of Arguments and Objects in User-Defined Functions.

Utility functions that implement and automate common sets of validation tasks. These functions are particularly useful to validate inputs, intermediate objects and output values in user-defined functions, resulting in tidier and less verbose functions.

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

CRANstatus BuildStatus R buildstatus pkgdown codecov License:MIT

Overview

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

  • inspect_prob() checks if an object is a numeric vector of valid probability values.

  • inspect_log_base() checks if an object is a valid logarithmic base.

  • inspect_true_or_false() checks if an object is a non-missing logical value.

  • inspect_bfactor() checks if an object is a numeric vector of valid Bayes factors values.

  • inspect_bfactor_log() checks if an object is a numeric vector of valid logarithmic Bayes factors values.

  • inspect_bfactor_scale() validates Bayes factor interpretation scales (from the pcal package).

  • inspect_categories() validates factor levels.

  • inspect_character() validates character vectors.

  • inspect_character_match() validates character values with predefined allowed values.

  • inspect_data_dichotomous() validates dichotomous data

  • inspect_data_categorical() and inspect_data_cat_as_dichotom() validate categorical data.

  • inspect_par_bernoulli() validates parameters for the Bernoulli and Binomial distributions.

  • inspect_par_multinomial() validates parameters for the Multinomial distribution.

  • inspect_par_beta() validates parameters for the Beta distribution.

  • inspect_par_dirichlet() validates parameters for the Dirichlet distribution.

  • inspect_par_haldane() validates parameters for the Haldane distribution.

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 [email protected].

References

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

Metadata

Version

1.0.3

License

Unknown

Platforms (75)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows