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) [1.6s]
#>  NC capture null: 51% (50/99) [1.8s]
#>  NC capture null: 61% (60/99) [2.1s]
#>  NC capture null: 71% (70/99) [2.3s]
#>  NC capture null: 81% (80/99) [2.5s]
#>  NC capture null: 91% (90/99) [2.8s]
#>  NC capture null: 100% (99/99) [3s]
#> $capture_R2
#> [1] 0.616692
#> 
#> $capture_pvalue
#> [1] 0
#> 
#> $capture_verdict
#> [1] "strong"
#> 
#> $null_distribution
#>  [1] 0.008724099 0.008928810 0.012081948 0.023921185 0.014254757 0.013333922
#>  [7] 0.029773923 0.016207649 0.032232805 0.032408672 0.020564075 0.025288176
#> [13] 0.021447251 0.017686638 0.018308490 0.014959142 0.034707614 0.017231756
#> [19] 0.025668071 0.024510220 0.029254301 0.015646657 0.020075614 0.037289204
#> [25] 0.014319553 0.017942267 0.019583425 0.029299869 0.023639253 0.026240893
#> [31] 0.011116603 0.010520650 0.017713280 0.021237523 0.014167138 0.026695385
#> [37] 0.025581615 0.014057918 0.014969354 0.028323007 0.008134256 0.007658334
#> [43] 0.018183770 0.008009030 0.023052488 0.019952585 0.007582754 0.013825606
#> [49] 0.019718216 0.013866528 0.024474821 0.031227315 0.008126219 0.006566353
#> [55] 0.019188921 0.016231317 0.019083737 0.016216128 0.018275726 0.023805869
#> [61] 0.023154481 0.018466259 0.024374756 0.027114979 0.014391975 0.014482670
#> [67] 0.019077723 0.019659838 0.014915116 0.018972154 0.010304153 0.031249417
#> [73] 0.008432791 0.028693459 0.031662725 0.023404222 0.019634002 0.019002577
#> [79] 0.027978437 0.028797877 0.010529774 0.044945821 0.035896621 0.013500541
#> [85] 0.025348244 0.024677247 0.014606582 0.024224230 0.020814065 0.017031917
#> [91] 0.043145251 0.017785751 0.010650629 0.017336114 0.020350415 0.020925617
#> [97] 0.017035801 0.018216804 0.019469662
#> 
#> $n_features
#> [1] 10
#>