library(tidyverse)
library(flipr)
<- 10
ngrid_in <- 100
ngrid_out <- 100000
nperms <- 30
n1 <- 30
n2 set.seed(1301)
<- rnorm(n1, mean = 0, sd = 1)
x1 <- rnorm(n2, mean = 3, sd = 1)
x2 <- rnorm(n1, mean = 0, sd = 1)
y1 <- rnorm(n2, mean = 0, sd = 2)
y2 <- rnorm(n1, mean = 0, sd = 1)
z1 <- rnorm(n2, mean = 3, sd = 2) z2
The concept of plausibility functions pertains to assessing the \(p\)-value of a set of null hypotheses and to plot this \(p\)-value surface on the domain defined by the set of null hypotheses. The idea behind is that, if such a plausibility function is available, you can deduce from it point estimates or confidence interval estimates for parameters used to define the nulls or extract a single \(p\)-value for a specific null of interest (Martin 2017; Fraser 2019; Infanger and Schmidt-Trucksäss 2019). In particular, there is another R package dedicated to plausibility functions called pvaluefunctions.
<- function(y, parameters) {
null_spec map(y, ~ .x - parameters)
}<- list(stat_t)
stat_functions <- list(delta = 1)
stat_assignments
<- PlausibilityFunction$new(
pf null_spec = null_spec,
stat_functions = stat_functions,
stat_assignments = stat_assignments,
x1, x2, seed = 1234
)$set_nperms(nperms)
pf$set_point_estimate(mean(x2) - mean(x1))
pf$set_parameter_bounds(
pfpoint_estimate = pf$point_estimate,
conf_level = pf$max_conf_level
)$set_grid(
pfparameters = pf$parameters,
npoints = ngrid_in
)
$set_alternative("two_tail")
pf$evaluate_grid(
pfgrid = pf$grid,
ncores = 1
)<- rename(pf$grid, two_tail = pvalue)
df
$set_alternative("left_tail")
pf$grid$pvalue <- NULL
pf$evaluate_grid(
pfgrid = pf$grid,
ncores = 1
)<- bind_rows(
df
df, rename(pf$grid, left_tail = pvalue)
)
$set_alternative("right_tail")
pf$grid$pvalue <- NULL
pf$evaluate_grid(
pfgrid = pf$grid,
ncores = 1
)<- bind_rows(
df
df, rename(pf$grid, right_tail = pvalue)
)
$set_grid(
pfparameters = pf$parameters,
npoints = ngrid_out
)
<- tibble(
df_mean delta = pf$grid$delta,
two_tail = approx(df$delta, df$two_tail, delta)$y,
left_tail = approx(df$delta, df$left_tail, delta)$y,
right_tail = approx(df$delta, df$right_tail, delta)$y,
%>%
) pivot_longer(-delta)
%>%
df_mean ggplot(aes(delta, value, color = name)) +
geom_line() +
labs(
title = "P-value function for the mean",
subtitle = "t-statistic",
x = expression(delta),
y = "p-value",
color = "Type"
+
) geom_hline(
yintercept = 0.05,
color = "black",
linetype = "dashed"
+
) geom_vline(
xintercept = mean(x2) - mean(x1),
color = "black"
+
) geom_vline(
xintercept = stats::t.test(x2, x1, var.equal = TRUE)$conf.int,
color = "black",
linetype = "dashed"
+
) scale_y_continuous(breaks = seq(0, 1, by = 0.05), limits = c(0, 1))
<- function(y, parameters) {
null_spec map(y, ~ .x / parameters)
}<- list(stat_f)
stat_functions <- list(rho = 1)
stat_assignments
<- PlausibilityFunction$new(
pf null_spec = null_spec,
stat_functions = stat_functions,
stat_assignments = stat_assignments,
y1, y2, seed = 1234
)$set_nperms(nperms)
pf$set_point_estimate(sd(y2) / sd(y1))
pf$set_parameter_bounds(
pfpoint_estimate = pf$point_estimate,
conf_level = pf$max_conf_level
)$set_grid(
pfparameters = pf$parameters,
npoints = ngrid_in
)
$set_alternative("two_tail")
pf$evaluate_grid(
pfgrid = pf$grid,
ncores = 1
)<- rename(pf$grid, two_tail = pvalue)
df
$set_alternative("left_tail")
pf$grid$pvalue <- NULL
pf$evaluate_grid(
pfgrid = pf$grid,
ncores = 1
)<- bind_rows(
df
df, rename(pf$grid, left_tail = pvalue)
)
$set_alternative("right_tail")
pf$grid$pvalue <- NULL
pf$evaluate_grid(
pfgrid = pf$grid,
ncores = 1
)<- bind_rows(
df
df, rename(pf$grid, right_tail = pvalue)
)
$set_grid(
pfparameters = pf$parameters,
npoints = ngrid_out
)
<- tibble(
df_sd rho = pf$grid$rho,
two_tail = approx(df$rho, df$two_tail, rho)$y,
left_tail = approx(df$rho, df$left_tail, rho)$y,
right_tail = approx(df$rho, df$right_tail, rho)$y,
%>%
) pivot_longer(-rho)
%>%
df_sd ggplot(aes(rho, value, color = name)) +
geom_line() +
labs(
title = "P-value function for the standard deviation",
subtitle = "F-statistic",
x = expression(rho),
y = "p-value",
color = "Type"
+
) geom_hline(
yintercept = 0.05,
color = "black",
linetype = "dashed"
+
) geom_vline(
xintercept = sqrt(stats::var.test(y2, y1)$statistic),
color = "black"
+
) geom_vline(
xintercept = sqrt(stats::var.test(y2, y1)$conf.int),
color = "black",
linetype = "dashed"
+
) scale_y_continuous(breaks = seq(0, 1, by = 0.05), limits = c(0, 1))
Assume that we have two r.v. \(X\) and \(Y\) that differ in distribution only in their first two moments. Let \(\mu_X\) and \(\mu_Y\) be the means of \(X\) and \(Y\) respectively and \(\sigma_X\) and \(\sigma_Y\) be the standard deviations. We can therefore write
\[ Y = \delta + \rho X. \]
In this case, we have
\[ \begin{cases} \mu_Y = \delta + \rho \mu_X \\ \sigma_Y^2 = \rho^2 \sigma_X^2 \end{cases} \Longleftrightarrow \begin{cases} \delta = \mu_Y - \frac{\sigma_Y}{\sigma_X} \mu_X \\ \rho = \frac{\sigma_Y}{\sigma_X} \end{cases} \]
In the following example, we have \(\delta = 3\) and \(\rho = 2\).
<- function(y, parameters) {
null_spec map(y, ~ (.x - parameters[1]) / parameters[2])
}<- list(stat_t, stat_f)
stat_functions <- list(delta = 1, rho = 2)
stat_assignments
<- PlausibilityFunction$new(
pf null_spec = null_spec,
stat_functions = stat_functions,
stat_assignments = stat_assignments,
z1, z2, seed = 1234
)$set_nperms(nperms)
pf$set_point_estimate(c(
pfmean(z2) - sd(z2) / sd(z1) * mean(z1),
sd(z2) / sd(z1)
))$set_parameter_bounds(
pfpoint_estimate = pf$point_estimate,
conf_level = pf$max_conf_level
)
# Fisher combining function
$set_aggregator("fisher")
pf$set_grid(
pfparameters = pf$parameters,
npoints = ngrid_in
)$evaluate_grid(grid = pf$grid, ncores = 1)
pf<- pf$grid
grid_in $set_grid(
pfparameters = pf$parameters,
npoints = ngrid_out
)if (requireNamespace("interp", quietly = TRUE)) {
<- interp::interp(
Zout x = grid_in$delta,
y = grid_in$log_rho,
z = grid_in$pvalue,
xo = sort(unique(pf$grid$delta)),
yo = sort(unique(pf$grid$log_rho))
)$grid$pvalue <- as.numeric(Zout$z)
pfelse
} $grid$pvalue <- rep(NA, nrow(pf$grid))
pf
<- pf$grid
df_fisher
# Tippett combining function
$set_aggregator("tippett")
pf$set_grid(
pfparameters = pf$parameters,
npoints = ngrid_in
)$evaluate_grid(grid = pf$grid, ncores = 1)
pf<- pf$grid
grid_in $set_grid(
pfparameters = pf$parameters,
npoints = ngrid_out
)if (requireNamespace("interp", quietly = TRUE)) {
<- interp::interp(
Zout x = grid_in$delta,
y = grid_in$log_rho,
z = grid_in$pvalue,
xo = sort(unique(pf$grid$delta)),
yo = sort(unique(pf$grid$log_rho))
)$grid$pvalue <- as.numeric(Zout$z)
pfelse
} $grid$pvalue <- rep(NA, nrow(pf$grid))
pf
<- pf$grid df_tippett
%>%
df_fisher ggplot(aes(delta, log_rho, z = pvalue)) +
geom_contour_filled(binwidth = 0.05) +
labs(
title = "Contour plot of the p-value surface",
subtitle = "Using Fisher's non-parametric combination",
x = expression(delta),
y = expression(log(rho)),
fill = "p-value"
+
) theme_minimal()
%>%
df_tippett ggplot(aes(delta, log_rho, z = pvalue)) +
geom_contour_filled(binwidth = 0.05) +
labs(
title = "Contour plot of the p-value surface",
subtitle = "Using Tippett's non-parametric combination",
x = expression(delta),
y = expression(log(rho)),
fill = "p-value"
+
) theme_minimal()