Skip to contents

Operationalizes the proximal completeness condition as whether the negative-control panel W captures the confounder covariance — i.e., whether adding W reduces U's contribution to the outcome toward zero.

Usage

nc_completeness_capture(
  dat,
  outcome = "Y",
  n_perm = 1000,
  n_cores = 1,
  thresholds = list(strong = 0.3, weak = 0.1)
)

Arguments

dat

Dataset list from run_single_iteration() or generate_toy_data(), containing W, an outcome block (Y or M), and synthetic_data (covariates).

outcome

Outcome block to test against: "Y" (default) or "M".

n_perm

Number of permutations for the null. Default 1000.

n_cores

Number of parallel workers. Default 1.

thresholds

Named list with strong and weak R^2 cutoffs for the verdict. Default list(strong = 0.3, weak = 0.1).

Value

A list with: capture_R2 (point estimate, averaged across outcome features), capture_pvalue (permutation p-value), capture_verdict ("strong", "weak", or "negligible"), null_distribution (numeric vector of permuted R^2 values), n_features (number of outcome features tested).

Details

The test computes the incremental R^2 of W for the outcome above covariates C alone: R^2(W | C) = R^2(Y ~ C + W) - R^2(Y ~ C), averaged across outcome features. A permutation null is generated by permuting the W-outcome association (holding the C-outcome association fixed) over n_perm permutations, yielding a permutation p-value for "W captures U-signal beyond chance."

This addresses the concern that the count-based completeness check (dim(W_valid) >= k) is necessary but not sufficient: completeness is about the covariance the controls capture, not the number of proxies. A panel can have many controls that each weakly capture U, or few controls that together capture it well.

Examples

dat <- run_single_iteration(n_features = 10, n_confounders = 1, seed = 1)
nc_completeness_capture(dat, n_perm = 99)
#> NC capture null: 99 tasks (sequential)
#>  NC capture null: 10% (10/99) [0.2s]
#>  NC capture null: 20% (20/99) [0.5s]
#>  NC capture null: 30% (30/99) [0.7s]
#>  NC capture null: 40% (40/99) [0.9s]
#>  NC capture null: 51% (50/99) [1.2s]
#>  NC capture null: 61% (60/99) [1.4s]
#>  NC capture null: 71% (70/99) [1.6s]
#>  NC capture null: 81% (80/99) [1.8s]
#>  NC capture null: 91% (90/99) [2.1s]
#>  NC capture null: 100% (99/99) [2.3s]
#> $capture_R2
#> [1] 0.616692
#> 
#> $capture_pvalue
#> [1] 0
#> 
#> $capture_verdict
#> [1] "strong"
#> 
#> $null_distribution
#>  [1] 0.023811221 0.010631048 0.010743923 0.012655256 0.017335406 0.021323739
#>  [7] 0.019705726 0.007496139 0.014059617 0.023486492 0.017275701 0.032740432
#> [13] 0.009844975 0.036229150 0.020553291 0.028758753 0.011437690 0.024856088
#> [19] 0.026455246 0.031542595 0.018638829 0.037088108 0.021689140 0.015296955
#> [25] 0.025209603 0.011135585 0.021571259 0.013427914 0.010231789 0.020427127
#> [31] 0.012818920 0.010615558 0.027752575 0.009953221 0.012910560 0.013654321
#> [37] 0.025559130 0.012157132 0.011736521 0.012591878 0.023153163 0.013070338
#> [43] 0.020114944 0.036173131 0.021618213 0.045410778 0.024944078 0.016637092
#> [49] 0.015602336 0.012542551 0.008437784 0.018127338 0.013196752 0.028421198
#> [55] 0.019143591 0.024692230 0.020443707 0.028283345 0.020310990 0.011208830
#> [61] 0.033341281 0.020795356 0.047075391 0.022070932 0.029307123 0.025713386
#> [67] 0.015758224 0.024023905 0.010762807 0.011960494 0.020773284 0.024551014
#> [73] 0.033713755 0.018759640 0.020459374 0.036386361 0.024725866 0.026594438
#> [79] 0.017608485 0.020512963 0.031217196 0.013761487 0.017590866 0.009599733
#> [85] 0.041777457 0.009716157 0.011334993 0.020738306 0.019375374 0.021590861
#> [91] 0.017783899 0.025111684 0.018242955 0.006558237 0.009532424 0.023175137
#> [97] 0.010620384 0.028225261 0.023452844
#> 
#> $n_features
#> [1] 10
#>