| Title: | Optimal Multiple Hypothesis Testing Corrections |
|---|---|
| Description: | Implements the optimal multiple hypothesis testing correction from Viviano, Wuthrich, and Niehaus (2026) <doi:10.48550/arXiv.2104.13367>. Derives the optimal per-test significance level from the economic incentives of research production, providing a correction that lies between Bonferroni (too conservative) and unadjusted (too permissive). Supports two cost models: a Linear one calibrated to United States Food and Drug Administration (FDA) clinical-trial costs, and a Cobb-Douglas one calibrated to Abdul Latif Jameel Poverty Action Lab (J-PAL) project costs. Reports optimal, Bonferroni, Holm, Benjamini-Hochberg (BH), and unadjusted results side by side. |
| Authors: | Davide Viviano [aut], Kaspar Wuthrich [aut], Paul Niehaus [aut], Erick Rosas Lopez [cre, ctb] |
| Maintainer: | Erick Rosas Lopez <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 1.0.0 |
| Built: | 2026-09-28 07:36:58 UTC |
| Source: | https://github.com/cran/mhtopt |
Estimates the parameters of the research cost function from data on project costs, number of treatment arms, and sample sizes. Implements the estimation approach from Section 6 and Appendix A of Viviano, Wuthrich, and Niehaus (2026).
mht_cost_estimate( cost, arms, sample_size, alpha_bar, model = c("cobbdouglas", "linear_share"), controls = NULL, robust = TRUE )mht_cost_estimate( cost, arms, sample_size, alpha_bar, model = c("cobbdouglas", "linear_share"), controls = NULL, robust = TRUE )
cost |
Numeric vector. Total project/trial costs. |
arms |
Numeric vector. Number of treatment arms in each study. |
sample_size |
Numeric vector. Sample size (total or per arm) in each study. |
alpha_bar |
Numeric. Benchmark single-hypothesis test size. |
model |
Character. |
controls |
Optional data frame of control variables to include in the regression. Columns will be added as covariates. |
robust |
Logical. Use heteroskedasticity-robust (HC1) standard errors.
Default |
A list of class "mht_cost_estimate" containing:
Model type used
The fitted lm object
Benchmark alpha
Estimated parameters (Cobb-Douglas)
Standard errors
P-values for H0: beta=0 and beta=1
P-values for H0: iota=0 and iota=1
Estimated fixed and variable costs (Linear)
Estimated fixed cost share (Linear)
Viviano, D., Wuthrich, K., and Niehaus, P. (2026). "A Model of Multiple Hypothesis Testing." arXiv:2104.13367v10. https://arxiv.org/abs/2104.13367
# Simulate data mimicking J-PAL cost structure set.seed(42) n <- 300 arms <- sample(1:5, n, replace = TRUE) sample_size <- sample(500:5000, n, replace = TRUE) cost <- exp(10 + 0.2 * log(arms) + 0.15 * log(sample_size) + rnorm(n, 0, 0.4)) # Estimate Cobb-Douglas cost function est <- mht_cost_estimate(cost, arms, sample_size, alpha_bar = 0.05) print(est) # Use estimated parameters to compute critical values mht_critical(J = 5, alpha_bar = 0.05, model = "cobbdouglas", beta = est$beta, iota = est$iota)# Simulate data mimicking J-PAL cost structure set.seed(42) n <- 300 arms <- sample(1:5, n, replace = TRUE) sample_size <- sample(500:5000, n, replace = TRUE) cost <- exp(10 + 0.2 * log(arms) + 0.15 * log(sample_size) + rnorm(n, 0, 0.4)) # Estimate Cobb-Douglas cost function est <- mht_cost_estimate(cost, arms, sample_size, alpha_bar = 0.05) print(est) # Use estimated parameters to compute critical values mht_critical(J = 5, alpha_bar = 0.05, model = "cobbdouglas", beta = est$beta, iota = est$iota)
Compute optimal critical values for multiple hypothesis testing based on
Proposition 4.1 of Viviano, Wuthrich, and Niehaus (2026). The optimal
per-test significance level is .
mht_critical( J, alpha_bar, model = c("linear", "cobbdouglas"), cf_share = 0.46, J_bar = 3, nm_ratio = 1, beta = 0.13, iota = 0.075 )mht_critical( J, alpha_bar, model = c("linear", "cobbdouglas"), cf_share = 0.46, J_bar = 3, nm_ratio = 1, beta = 0.13, iota = 0.075 )
J |
Integer or |
alpha_bar |
Numeric. Benchmark single-hypothesis test size (e.g., 0.05). |
model |
Character. Cost model: |
cf_share |
Numeric. Fixed cost share for the Linear model. Default 0.46, based on Sertkaya et al. (2016). |
J_bar |
Numeric. Average number of subgroups across trials (Linear model). Default 3, based on Pocock et al. (2002). |
nm_ratio |
Numeric. Ratio of per-arm sample size to benchmark
( |
beta |
Numeric. Elasticity of cost with respect to number of arms (Cobb-Douglas model). Default 0.13 (J-PAL estimate). |
iota |
Numeric. Elasticity of cost with respect to sample size (Cobb-Douglas model). Default 0.075 (J-PAL estimate). |
A list of class "mht_critical" containing:
Optimal per-test significance level
Optimal z-threshold (critical value for one-sided test)
Bonferroni significance level (); 0 when J = Inf
Bonferroni z-threshold
Sidak significance level ; 0 when J = Inf
Sidak z-threshold
Benchmark alpha
Number of hypotheses (may be Inf)
Sample size ratio used
Cost model used
Viviano, D., Wuthrich, K., and Niehaus, P. (2026). "A Model of Multiple Hypothesis Testing." arXiv:2104.13367v10. https://arxiv.org/abs/2104.13367
# Linear calibration: 5 hypotheses, benchmark alpha = 0.05 mht_critical(J = 5, alpha_bar = 0.05) # Limiting case J -> Inf mht_critical(J = Inf, alpha_bar = 0.025) # Cobb-Douglas (J-PAL calibration) mht_critical(J = 5, alpha_bar = 0.05, model = "cobbdouglas", beta = 0.13, iota = 0.075) # Linear model with larger sample mht_critical(J = 3, alpha_bar = 0.025, nm_ratio = 1.5)# Linear calibration: 5 hypotheses, benchmark alpha = 0.05 mht_critical(J = 5, alpha_bar = 0.05) # Limiting case J -> Inf mht_critical(J = Inf, alpha_bar = 0.025) # Cobb-Douglas (J-PAL calibration) mht_critical(J = 5, alpha_bar = 0.05, model = "cobbdouglas", beta = 0.13, iota = 0.075) # Linear model with larger sample mht_critical(J = 3, alpha_bar = 0.025, nm_ratio = 1.5)
Extracts coefficient estimates, standard errors, and p-values from a fitted
regression object and applies the optimal MHT adjustment from Proposition 4.1
of Viviano, Wuthrich, and Niehaus (2026). This is the standard research
workflow interface: run a regression, then call mht_est() on
the result.
mht_est( fit, vars = NULL, alpha_bar, onesided = TRUE, model = c("linear", "cobbdouglas"), cf_share = 0.46, J_bar = 3, nm_ratio = 1, mbar = NULL, beta = 0.13, iota = 0.075 )mht_est( fit, vars = NULL, alpha_bar, onesided = TRUE, model = c("linear", "cobbdouglas"), cf_share = 0.46, J_bar = 3, nm_ratio = 1, mbar = NULL, beta = 0.13, iota = 0.075 )
fit |
A fitted model object. See Details for supported classes. |
vars |
Character vector of coefficient names to test. If |
alpha_bar |
Numeric. Benchmark single-hypothesis significance level (e.g., 0.05). |
onesided |
Logical. If |
model |
Character. Cost model: |
cf_share |
Numeric. Fixed cost share (Linear model). Default 0.46. |
J_bar |
Numeric. Average number of subgroups (Linear model). Default 3. |
nm_ratio |
Numeric. Sample size ratio n_bar/m_bar. Default 1.0.
Overridden by |
mbar |
Numeric or |
beta |
Numeric. Arms elasticity (Cobb-Douglas). Default 0.13. |
iota |
Numeric. Sample size elasticity (Cobb-Douglas). Default 0.075. |
Supported model classes:
lm, glm (base R)
lm_robust, iv_robust (estimatr package)
fixest class objects, e.g. feols(), fepois() (fixest package)
Any other class with a coef(summary(fit)) method returning a
standard 4-column matrix (Estimate, Std. Error, t/z value, Pr(>|t|)) will
also work.
A data frame of class c("mht_est", "data.frame") with
columns:
Coefficient name
Point estimate
Standard error
t- or z-statistic
p-value used for testing (one-sided if onesided=TRUE)
Logical. Rejection under optimal model-based procedure
Logical. Rejection under Bonferroni
Logical. Rejection under Holm step-down
Logical. Rejection under Benjamini-Hochberg (FDR)
Logical. Rejection without adjustment
Attributes alpha_opt, alpha_bonf, alpha_bar,
J, and model are attached.
Most estimation functions return two-sided p-values. By default
(onesided = TRUE), this function converts to one-sided p-values in
the positive direction. This is theoretically grounded in Remark 6
of the paper: under Assumptions 2–4 (linearity, welfare additivity, and
normality), one-sided t-tests are globally optimal. The key
assumption is that the status quo (the baseline policy) remains in
place whenever the researcher does not report a positive finding. Negative
treatment effects therefore never lead to rejection (welfare gains require
positive effects).
Two-sided tests (onesided = FALSE) are appropriate when
there is uncertainty about the policymaker's default action — i.e., the
policymaker may implement a treatment even in the absence of a positive
recommendation. Appendix B.2 (Proposition 9) of the paper shows
that in this extended model, two-sided t-tests with the same
critical threshold
are maximin optimal.
Conversion when onesided = TRUE:
If t-statistic >= 0: p_one = p_two / 2
If t-statistic < 0: p_one = 1 - p_two / 2
A negative effect is never rejected (p_one > 0.5 for t < 0).
Viviano, D., Wuthrich, K., and Niehaus, P. (2026). "A Model of Multiple Hypothesis Testing." arXiv:2104.13367v10. https://arxiv.org/abs/2104.13367
mht_test for direct p-value input,
mht_critical for computing critical values only.
# Basic usage with lm() data(mtcars) fit <- lm(mpg ~ cyl + hp + wt + am, data = mtcars) mht_est(fit, vars = c("cyl", "hp", "wt", "am"), alpha_bar = 0.05) # With Cobb-Douglas model mht_est(fit, vars = c("cyl", "hp", "wt", "am"), alpha_bar = 0.05, model = "cobbdouglas", beta = 0.13, iota = 0.075) # Two-sided test (e.g., for a two-sided hypothesis) mht_est(fit, vars = c("cyl", "hp", "wt"), alpha_bar = 0.05, onesided = FALSE) # With estimatr::lm_robust(), when that suggested package is available if (requireNamespace("estimatr", quietly = TRUE)) { fit_r <- estimatr::lm_robust(mpg ~ cyl + hp + wt, data = mtcars) print(mht_est(fit_r, vars = c("cyl", "hp", "wt"), alpha_bar = 0.05)) } # With fixest::feols(), when that suggested package is available if (requireNamespace("fixest", quietly = TRUE)) { fit_fe <- fixest::feols(mpg ~ cyl + hp + wt | gear, data = mtcars) print(mht_est(fit_fe, vars = c("cyl", "hp", "wt"), alpha_bar = 0.05)) }# Basic usage with lm() data(mtcars) fit <- lm(mpg ~ cyl + hp + wt + am, data = mtcars) mht_est(fit, vars = c("cyl", "hp", "wt", "am"), alpha_bar = 0.05) # With Cobb-Douglas model mht_est(fit, vars = c("cyl", "hp", "wt", "am"), alpha_bar = 0.05, model = "cobbdouglas", beta = 0.13, iota = 0.075) # Two-sided test (e.g., for a two-sided hypothesis) mht_est(fit, vars = c("cyl", "hp", "wt"), alpha_bar = 0.05, onesided = FALSE) # With estimatr::lm_robust(), when that suggested package is available if (requireNamespace("estimatr", quietly = TRUE)) { fit_r <- estimatr::lm_robust(mpg ~ cyl + hp + wt, data = mtcars) print(mht_est(fit_r, vars = c("cyl", "hp", "wt"), alpha_bar = 0.05)) } # With fixest::feols(), when that suggested package is available if (requireNamespace("fixest", quietly = TRUE)) { fit_fe <- fixest::feols(mpg ~ cyl + hp + wt | gear, data = mtcars) print(mht_est(fit_fe, vars = c("cyl", "hp", "wt"), alpha_bar = 0.05)) }
Generates a table of optimal critical values for a range of hypothesis counts and sample size ratios, reproducing Table 1 in Viviano, Wuthrich, and Niehaus (2026) (linear calibration) or the J-PAL Cobb-Douglas calibration.
mht_table( alpha_bar = c(0.025, 0.05, 0.1, 0.15), J_range = c(1:9, Inf), nm_ratios = c(0.5, 1, 1.5, 2), sidak_bars = c(0.025, 0.05), model = c("linear", "cobbdouglas"), ... )mht_table( alpha_bar = c(0.025, 0.05, 0.1, 0.15), J_range = c(1:9, Inf), nm_ratios = c(0.5, 1, 1.5, 2), sidak_bars = c(0.025, 0.05), model = c("linear", "cobbdouglas"), ... )
alpha_bar |
Numeric vector. Benchmark single-hypothesis sizes for the
optimal columns. Default |
J_range |
Numeric vector. Hypothesis counts (rows). May include
|
nm_ratios |
Numeric vector. Sample size ratios |
sidak_bars |
Numeric vector. |
model |
Character. Cost model: |
... |
Additional arguments passed to |
The default arguments reproduce Table 1 of the paper exactly: rows for
, four columns at
, single-column groups at 50\
(all with ), and Sidak benchmark columns for
.
A data frame (class "mht_table") with columns:
J: hypothesis count (may include Inf)
a<ab>_nm<nm>: optimal alpha for each (alpha_bar, nm_ratio) pair
sidak_<ab>: Sidak level for each sidak_bars value
Viviano, D., Wuthrich, K., and Niehaus, P. (2026). "A Model of Multiple Hypothesis Testing." arXiv:2104.13367v10. https://arxiv.org/abs/2104.13367
# Reproduce Table 1 exactly (v10) mht_table() # Cobb-Douglas with J-PAL parameters, no Sidak columns mht_table(model = "cobbdouglas", beta = 0.13, iota = 0.075, sidak_bars = NULL) # Custom range, single alpha mht_table(alpha_bar = 0.05, J_range = 1:20, nm_ratios = 1.0, sidak_bars = NULL)# Reproduce Table 1 exactly (v10) mht_table() # Cobb-Douglas with J-PAL parameters, no Sidak columns mht_table(model = "cobbdouglas", beta = 0.13, iota = 0.075, sidak_bars = NULL) # Custom range, single alpha mht_table(alpha_bar = 0.05, J_range = 1:20, nm_ratios = 1.0, sidak_bars = NULL)
Given p-values or test statistics, applies the model-optimal MHT adjustment from Proposition 4.1 of Viviano, Wuthrich, and Niehaus (2026) and returns rejection decisions compared across multiple procedures.
mht_test( p = NULL, z = NULL, alpha_bar, model = c("linear", "cobbdouglas"), cf_share = 0.46, J_bar = 3, nm_ratio = 1, beta = 0.13, iota = 0.075 )mht_test( p = NULL, z = NULL, alpha_bar, model = c("linear", "cobbdouglas"), cf_share = 0.46, J_bar = 3, nm_ratio = 1, beta = 0.13, iota = 0.075 )
p |
Numeric vector. One-sided p-values. Provide either |
z |
Numeric vector. Z-statistics. If provided, p-values are computed as
|
alpha_bar |
Numeric. Benchmark single-hypothesis test size. |
model |
Character. Cost model: |
cf_share |
Numeric. Fixed cost share (Linear model). Default 0.46. |
J_bar |
Numeric. Average number of subgroups (Linear model). Default 3. |
nm_ratio |
Numeric. Sample size ratio. Default 1.0. |
beta |
Numeric. Arms elasticity (Cobb-Douglas). Default 0.13. |
iota |
Numeric. Sample size elasticity (Cobb-Douglas). Default 0.075. |
A data frame of class "mht_test" with columns:
Input p-values
Rejection under the optimal model-based procedure
Rejection under Bonferroni correction
Rejection under Holm's step-down procedure
Rejection under Benjamini-Hochberg (FDR) control
Rejection without adjustment
The object also carries attributes alpha_opt, alpha_bonf,
alpha_bar, J, and model.
Viviano, D., Wuthrich, K., and Niehaus, P. (2026). "A Model of Multiple Hypothesis Testing." arXiv:2104.13367v10. https://arxiv.org/abs/2104.13367
# Test with p-values pvals <- c(0.003, 0.015, 0.030, 0.048, 0.120, 0.500) result <- mht_test(p = pvals, alpha_bar = 0.05) print(result) # Test with z-statistics zstats <- qnorm(1 - pvals) result2 <- mht_test(z = zstats, alpha_bar = 0.05) # Cobb-Douglas model result3 <- mht_test(p = pvals, alpha_bar = 0.05, model = "cobbdouglas")# Test with p-values pvals <- c(0.003, 0.015, 0.030, 0.048, 0.120, 0.500) result <- mht_test(p = pvals, alpha_bar = 0.05) print(result) # Test with z-statistics zstats <- qnorm(1 - pvals) result2 <- mht_test(z = zstats, alpha_bar = 0.05) # Cobb-Douglas model result3 <- mht_test(p = pvals, alpha_bar = 0.05, model = "cobbdouglas")