Skip to contents

Construct test objects in a unified way.

Usage

pmt(key, ...)

pmts(
  which = c("all", "onesample", "twosample", "distribution", "association", "paired",
    "ksample", "multcomp", "rcbd", "table")
)

define_pmt(
  method = c("twosample", "distribution", "association", "paired", "ksample", "rcbd",
    "table"),
  statistic,
  rejection = c("<>", "<", ">"),
  scoring = "none",
  n_permu = 10000,
  name = "User-Defined Permutation Test",
  alternative = NULL,
  depends = character(),
  plugins = character(),
  includes = character()
)

Arguments

key

a character string specifying the test. Check pmts() for valid keys.

...

extra parameters passed to the constructor.

which

a character string specifying the desired tests.

method

a character string specifying the permutation scheme.

statistic

definition of the test statistic. See details.

rejection

a character string specifying the rejection region relative to the test statistic.

scoring

one of: - a character string in c("none", "rank", "vw", "expon") specifying the scoring system - a function that takes a numeric vector and returns an equal-length score vector

n_permu

an integer indicating number of permutations for the permutation distribution. If set to 0, all permutations will be used.

name, alternative

character strings specifying the name of the test and the alternative hypothesis, used for printing purposes only.

depends, plugins, includes

passed to Rcpp::cppFunction().

Value

a test object corresponding to the specified key.

a data frame containing keys and corresponding tests implemented in this package.

a test object based on the specified statistic.

Details

The test statistic can be defined using either R or Rcpp, with the statistic parameter specified as:

  • R: a function returning a closure that returns a double.

  • Rcpp: a character string defining a captureless lambda (since C++11) returning another lambda that captures by value, accepts parameters of the same type, and returns a double.

The purpose of this design is to pre-calculate certain constants that remain invariant during permutation.

When using Rcpp, the parameters for different method are listed as follows. Note that the names can be customized, and the types can be replaced with auto (thanks to the support for generic lambdas in C++14). See examples.

methodParameter 1Parameter 2
"twosample"const NumericVector& sample_1const NumericVector& sample_2
"distribution"const NumericVector& cumulative_prob_1const NumericVector& cumulative_prob_2
"association"const NumericVector& sample_1const NumericVector& sample_2
"paired"const NumericVector& sample_1const NumericVector& sample_2
"ksample"const NumericVector& combined_sampleconst IntegerVector& one_based_group_index
"rcbd"const NumericMatrix& block_as_column_data
"table"const IntegerMatrix& contingency_table

When using R, the parameters should be the R equivalents of these.

Note

To improve performance when calling R functions from C++, this package repeatedly evaluates the function body of the inner closure in the same environment, where formal arguments are pre-assigned to the data and the enclosing environment is that of the closure. This imposes the following restrictions on the inner closure when statistic is written in R:

  • Do not reassign the inner closure’s formal arguments or any pre-computed symbols in the outer closure.

  • Do not use default arguments or variadic arguments.

It's also worth noting that the data is permuted in-place. Therefore, modifications to the data within statistic may lead to incorrect results. It is recommended to avoid modifying the data when using R and pass const references as in the table above when using Rcpp.

Examples

pmt("twosample.wilcoxon")
#> <Wilcoxon>
#>   Inherits from: <TwoSampleLocationTest>
#>   Public:
#>     alternative: active binding
#>     conf_int: active binding
#>     conf_level: active binding
#>     correct: active binding
#>     data: active binding
#>     estimate: active binding
#>     initialize: function (type = c("permu", "asymp"), alternative = c("two_sided", 
#>     method: active binding
#>     n_permu: active binding
#>     null_value: active binding
#>     p_value: active binding
#>     plot: function (style = c("graphics", "ggplot2"), ...) 
#>     print: function () 
#>     scoring: active binding
#>     statistic: active binding
#>     test: function (...) 
#>     type: active binding
#>   Private:
#>     .alternative: two_sided
#>     .autoplot: function (...) 
#>     .calculate: function () 
#>     .calculate_extra: function () 
#>     .calculate_n_permu: function () 
#>     .calculate_p: function () 
#>     .calculate_p_permu: function () 
#>     .calculate_score: function () 
#>     .calculate_side: function () 
#>     .calculate_statistic: function () 
#>     .compile: function () 
#>     .conf_int: NULL
#>     .conf_level: 0.95
#>     .correct: TRUE
#>     .data: NULL
#>     .define: function () 
#>     .estimate: NULL
#>     .link: +
#>     .method: default
#>     .n_permu: 10000
#>     .name: Two-Sample Wilcoxon Test
#>     .null_value: 0
#>     .on_alternative_change: function () 
#>     .on_conf_level_change: function () 
#>     .on_method_change: function () 
#>     .on_n_permu_change: function () 
#>     .on_null_value_change: function () 
#>     .on_scoring_change: function () 
#>     .on_type_change: function () 
#>     .p_value: NULL
#>     .param_name: location shift
#>     .plot: function (...) 
#>     .preprocess: function () 
#>     .print: function () 
#>     .raw_data: NULL
#>     .scoring: rank
#>     .side: NULL
#>     .statistic: NULL
#>     .statistic_func: NULL
#>     .type: permu

pmts("ksample")
#>              key              class                         test
#> 1 ksample.oneway             OneWay One-Way Test for Equal Means
#> 2     ksample.kw      KruskalWallis          Kruskal-Wallis Test
#> 3     ksample.jt JonckheereTerpstra     Jonckheere-Terpstra Test

x <- rnorm(5)
y <- rnorm(5, 1)

t <- define_pmt(
    method = "twosample", rejection = "<",
    scoring = base::rank, # equivalent to "rank"
    statistic = function(...) function(x, y) sum(x)
)$test(x, y)$print()
#> 
#>  	 User-Defined Permutation Test 
#> 
#> scoring: custom    type: permu(10000)    method: twosample
#> statistic = 29, p-value = 0.6564 (± 0.009308055 at 95% confidence)

t$scoring <- function(x) qnorm(rank(x) / (length(x) + 1)) # equivalent to "vw"
t$print()
#> 
#>  	 User-Defined Permutation Test 
#> 
#> scoring: custom    type: permu(10000)    method: twosample
#> statistic = 0.3487557, p-value = 0.5975 (± 0.009611695 at 95% confidence)

t$n_permu <- 0
t$print()
#> 
#>  	 User-Defined Permutation Test 
#> 
#> scoring: custom    type: permu(252)    method: twosample
#> statistic = 0.3487557, p-value = 0.6031746

# \donttest{
r <- define_pmt(
    method = "twosample", n_permu = 1e5,
    statistic = function(x, y) {
        m <- length(x)
        n <- length(y)
        function(x, y) sum(x) / m - sum(y) / n
    }
)


rcpp <- define_pmt(
    method = "twosample", n_permu = 1e5,
    statistic = "[](const auto& x, const auto& y) {
        auto m = x.length();
        auto n = y.length();
        return [=](const auto& x, const auto& y) {
            return sum(x) / m - sum(y) / n;
        };
    }"
)

# equivalent
# rcpp <- define_pmt(
#     method = "twosample", n_permu = 1e5,
#     statistic = "[](const NumericVector& x, const NumericVector& y) {
#         R_xlen_t m = x.length();
#         R_xlen_t n = y.length();
#         return [m, n](const NumericVector& x, const NumericVector& y) -> double {
#             return sum(x) / m - sum(y) / n;
#         };
#     }"
# )

options(LearnNonparam.pmt_progress = FALSE)
system.time(r$test(x, y))
#>    user  system elapsed 
#>   0.084   0.000   0.084 
system.time(rcpp$test(x, y))
#>    user  system elapsed 
#>   0.008   0.000   0.008 
# }