knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "man/figures/README-", out.width = "100%" ) library(inspector)
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.
The development version of inspector
can be installed from
Github with the devtools
package:
# install.packages("devtools") devtools::install_github("ptfonseca/inspector")
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)
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)
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)
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 @bergerDelampady1987, 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))
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))
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.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.