Assesses how sensitive a matched-pair analysis is to unmeasured confounding using the Rosenbaum bounds framework. For each value of the sensitivity parameter Gamma – the maximum odds ratio for differential treatment assignment within a matched pair due to hidden bias – the function reports the upper and lower bounds on the p-value of the Wilcoxon signed-rank test.
Usage
sa_rosenbaum(
x,
outcome_col,
gamma_max = 3,
gamma_inc = 0.25,
alpha = 0.05,
treatment_col = NULL,
pair_id_col = "pair_id",
treated_level = NULL,
alternative = c("auto", "greater", "less")
)Arguments
- x
A
ps_matchobject (returned byps_match()) or a plain data frame whose rows are matched patients.- outcome_col
Name of the numeric outcome column. Required.
- gamma_max
Maximum Gamma to test. Default
3.- gamma_inc
Increment between Gamma values. Default
0.25.- alpha
Significance threshold. Default
0.05.- treatment_col
Name of the binary treatment column (0/1). Taken from
x$meta$treatment_colwhenxis aps_matchobject. Required whenxis a plain data frame.- pair_id_col
Name of the pair-ID column created by
ps_match(). Taken fromx$meta$pair_id_colwhen recorded. Default"pair_id".- treated_level
The value of
treatment_colthat is treated. Read from the metadata of aps_dataobject when it records one.NULL(default) requires a 0/1 or logical column and takes 1 orTRUE.- alternative
Direction of the test:
"auto"(default; chosen from the sign of the median difference, see Details),"greater"(treated outcome above control) or"less".
Value
An object of class c("sa_rosenbaum", "ps_data"):
$dataThe input data frame (
x$datafor aps_matchobject).$metaColumn names,
treated_level, the settings (gamma, the grid tested,gamma_max,gamma_inc,alpha,alternative, the direction tested, anddirection_from_data), and the results:sensitivity_value, the largest Gamma for which the upper p-value is belowalpha(NAif the analysis is not significant at Gamma = 1),n_pairs, the complete matched pairs used,n_dropped,n_nonzeroand the statistict_plus.$tables$boundsData frame with columns
gamma,p_upper,p_lower,reject_upper(logical – is the upper bound <alpha?).$tables$pairsOne row per complete pair:
pair_id,treatedandcontroloutcomes, anddifference.$modelsAn empty list.
Details
A Gamma of 1 corresponds to no hidden bias (equivalent to perfect
randomisation within pairs). The sensitivity value is the largest Gamma
at which the upper p-value bound remains below alpha; a larger sensitivity
value indicates a more robust result.
The statistic is the Wilcoxon signed-rank sum \(T^+\) of the ranks of
\(|d_i|\) over pairs with \(d_i > 0\), where \(d_i\) is the treated
minus the control outcome and zero differences are dropped. Tied
\(|d_i|\) take their average rank. Under hidden bias Gamma each pair is
positive with probability at most \(p^+ = \Gamma / (1 + \Gamma)\), so the
worst-case null distribution has mean \(p^+ \sum r_i\) and variance
\(p^+ (1 - p^+) \sum r_i^2\), and the best case uses
\(p^- = 1 / (1 + \Gamma)\). Using \(\sum r_i^2\) rather than
\(n(n+1)(2n+1)/6\) corrects the variance for ties; without ties the two
agree. The p-values use the normal approximation with a continuity
correction of 0.5, so at Gamma = 1 they equal the one-sided
stats::wilcox.test() p-value with exact = FALSE and correct = TRUE.
Rosenbaum's method assumes the direction of the test is fixed before the
outcome is seen. Set alternative to "greater" (treated above control)
or "less" to state it. The default "auto" keeps the earlier behaviour
and picks the direction from the data: it tests the lower tail, with a
warning, when the median nonzero difference is negative. A direction
chosen from the data makes the bounds slightly optimistic, so prefer an
explicit alternative in a pre-specified analysis.
Column names and the treated level are read from a ps_match() object's
metadata. A supplied treatment_col, pair_id_col or treated_level
must agree with that metadata; a conflict aborts.
Examples
dta <- sample_ps_data(n = 300, seed = 1)
m <- ps_match(dta)
res <- sa_rosenbaum(m, outcome_col = "ef", gamma_max = 2, alternative = "greater")
res
#> <sa_rosenbaum>
#> Outcome : ef (greater, 300 pairs)
#> Sensitivity : Gamma = 1.75 at alpha = 0.05
#> gamma p_upper p_lower reject_upper
#> 1.00 5.990619e-11 5.990619e-11 TRUE
#> 1.25 7.884045e-07 2.220446e-16 TRUE
#> 1.50 2.257868e-04 0.000000e+00 TRUE
#> 1.75 7.391183e-03 0.000000e+00 TRUE
#> 2.00 6.394389e-02 0.000000e+00 FALSE
res$tables$bounds
#> gamma p_upper p_lower reject_upper
#> 1 1.00 5.990619e-11 5.990619e-11 TRUE
#> 2 1.25 7.884045e-07 2.220446e-16 TRUE
#> 3 1.50 2.257868e-04 0.000000e+00 TRUE
#> 4 1.75 7.391183e-03 0.000000e+00 TRUE
#> 5 2.00 6.394389e-02 0.000000e+00 FALSE
res$meta$sensitivity_value
#> [1] 1.75