Skip to contents

For binary treatment \(T\), covariates \(Z\) and outcome \(Y\), it tests the hypothesis $$H_0^c(S): \tau(Z) \text{ only depends on } Z \text{ through } Z_{S^c},$$ where \(S\) is a subset of covariates and \(\tau(Z)=\mathbb{E}[Y | T=1, Z] - \mathbb{E}[Y | T=0, Z]\) is the CATE. When \(S\) is the full set, this amounts to testing \(\tau(Z)\) is a constant; when \(S\) is a proper subset, this amounts to testing \(Z_S\) has no further effect modification while holding \(Z_{S^c}\) fixed.

Usage

hte_test_conditional(
  y,
  Tr,
  Z,
  S = 1:ncol(Z),
  hunt.style = "optimal",
  folds.crossfit = 5,
  trim.outlier.hunt = TRUE,
  splits = c(0.5, 0.5),
  arg.hunt_grf = list(honesty = FALSE, tune.parameters = "all"),
  verbose = FALSE,
  randomized = FALSE
)

Arguments

y

Numeric response vector of length n.

Tr

Binary (0/1) treatment vector of length n.

Z

Numeric covariate matrix of dimension n x p.

S

A subset of 1:ncol(Z) giving the covariates whose effect modification is tested (they have none under the null, given the rest). Default 1:ncol(Z) tests for any heterogeneity (constant CATE under the null); S = NULL leaves the CATE unrestricted.

hunt.style

One of "optimal" (default), "wls" or "vanilla", selecting the hunting algorithm in dScoreTest. The hunted alternative is a grf outcome model fitted separately for the treated and control arms (T-learner).

folds.crossfit

Number of cross-fitting folds passed to fit_CATE when estimating the CATE. Default 5.

trim.outlier.hunt, splits, verbose

Passed through to dScoreTest; see there for details.

arg.hunt_grf

Arguments passed to grf::regression_forest() for hunting.

randomized

If FALSE (default), the propensity \(e(Z) = \mathbb{E}[T \mid Z]\) used by fit_CATE and by the debiasing step is estimated with grf::probability_forest. If TRUE, T is assumed randomized (independent of Z), so \(e(Z)\) is taken to be the constant mean(T), fitted upfront without cross-fitting.

Value

An object of class "dScoreTest": a list whose key elements are the debiased test statistic t.stat and the one-sided p-value p.val (right tail of the standard normal), along with the test-set score residuals, the hunted direction, and the call. It has print, summary and plot methods.

References

Dhawan, A., Guo, F. R. and Shah, R. D. (2026). The debiased score test: hunt-and-test for semiparametric hypotheses. arXiv:2607.28861. https://arxiv.org/abs/2607.28861

See also

Examples

 set.seed(1)
 n <- 600
 Z  <- matrix(rnorm(n * 3), n, 3)
 Tr <- rbinom(n, 1, plogis(Z[, 1]))
 y  <- Z[, 2] + Z[, 3] + Tr * (1 + Z[, 1]) + rnorm(n)  # CATE varies with Z1
 # \donttest{
 # allow modification by Z1 (S = {2,3}): well-specified, should not reject
 hte_test_conditional(y, Tr, Z, S = c(2, 3))
#> Debiased score test: 
#> y ~ X, with X consists of T, Z1, Z2, Z3.
#> (hunt.style = optimal, hunt.method = grf.hte, debias.method = hte.conditional)
#> n = 600, two-way split: hunt = 300, debias & test = 300
#> 
#> T = 0.5666, p-value = 0.285481
 # forbid all modification (constant CATE): misspecified, should reject
 hte_test_conditional(y, Tr, Z, S = 1:3)
#> Debiased score test: 
#> y ~ X, with X consists of T, Z1, Z2, Z3.
#> (hunt.style = optimal, hunt.method = grf.hte, debias.method = hte.conditional)
#> n = 600, two-way split: hunt = 300, debias & test = 300
#> 
#> T = 3.8425, p-value = 6.08863e-05
 # }