| Title: | Network-Constrained Matching and Randomization-Based Inference |
|---|---|
| Description: | Provides network-constrained matching and randomization-based inference for observational network data with dependence and interference. Dual-penalty matching minimizes total covariate dissimilarity while enforcing penalties on network proximity between and within treatment arms in matched sets. Randomization-based inference combines evidence from correlated matched sets based on this design. The package also provides covariate-balance and network-distance diagnostics, sensitivity analysis, and simulated example data. The open-source 'HiGHS' solver is used by default to solve the matching problem. An optional interface to the commercial 'Gurobi Optimizer' is available. Eligible academic users can request a free license at <https://www.gurobi.com/academics/>. The optimizer can be downloaded from <https://www.gurobi.com/product/download-center>. The associated 'gurobi' R package is not available from CRAN; it is distributed with the optimizer and can be installed by following the official instructions at <https://docs.gurobi.com/projects/optimizer/en/current/reference/r/setup.html>. |
| Authors: | Zhejia Dong [aut, cre] |
| Maintainer: | Zhejia Dong <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-15 17:20:59 UTC |
| Source: | https://github.com/cran/netmatchRI |
netmatchRI provides network-constrained matching and randomization-based inference for observational network data. Dual-penalty matching minimizes total covariate dissimilarity while enforcing penalties on network proximity between and within treatment arms in matched sets. Randomization-based inference combines evidence from correlated matched sets based on this design.
Use netmatch() to construct a dual-penalty, single-penalty, or
covariate-only matched design. Inspect the result with summary(),
matched_data(), and diagnose_match(), which checks
covariate balance and within-set network distances. Compare selected
matching designs with plot_covariate_balance() and
plot_covariate_similarity(). Use RI_unadjusted(),
RI_adjusted(), or RI_design() for inference, and use
sensitivity_grid(), critical_sensitivity(), and
plot_sensitivity() to examine sensitivity to residual network
dependence.
Dual-penalty matching uses the open-source HiGHS solver by default. The
solver argument can select HiGHS, Gurobi, or GLPK;
solver = "auto" tries them in that order of availability.
netmatch_example contains the fixed data and network used in the guide.
simulate_netmatch_example() generates new simulated network data.
Computes critical eta values where the p-value equals alpha,
together with critical eta at
rho = 1 and the critical ratio.
critical_sensitivity(match, outcome, rho = seq(0, 1, by = 0.01), alpha = 0.05, kappa = NULL, weight_type = c("ns", "ntc"))critical_sensitivity(match, outcome, rho = seq(0, 1, by = 0.01), alpha = 0.05, kappa = NULL, weight_type = c("ns", "ntc"))
match |
A |
outcome |
Name of the numeric outcome column. |
rho |
Sensitivity-decay values in |
alpha |
Test level. Default: |
kappa |
Network distance threshold. |
weight_type |
Matched-set weighting. |
Let be the minimum network distance between units in matched
sets and . For pairs with ,
the sensitivity bound is
.
At a critical contour point, its value is the critical sensitivity bound
.
Within the parameter range, eta values below the critical curve retain
rejection and values above it do not. On the curve, the p-value equals
alpha.
Let be the number of matched sets and the number of
relevant matched-set pairs. The critical ratio is
Here, is the matched-set weight and is the
variance of its Mann–Whitney U statistic. The numerator averages the weighted
covariance bounds over pairs with minimum distance at most kappa;
the denominator averages the weighted within-set variances. The ratio is
constant along the critical curve.
The summary's critical_ratio is NA when no critical
contour is attained within the range. If the baseline p-value is greater
than alpha, critical eta is NA. If the baseline p-value equals
alpha and the sensitivity denominator is positive, critical eta and
the ratio are zero.
A netmatch_critical_sensitivity object. summary reports the
critical eta at rho = 1 and the critical ratio; curve contains the
critical eta over the requested rho values; detail contains the supporting
counts and averages. The object also retains the analysis settings and matched
design.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2) crit <- critical_sensitivity(m, "Y", rho = seq(0, 1, by = 0.25)) crit crit$summary crit$curvedata("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2) crit <- critical_sensitivity(m, "Y", rho = seq(0, 1, by = 0.25)) crit crit$summary crit$curve
Checks covariate balance and network distance within matched sets.
diagnose_match(match)diagnose_match(match)
match |
A |
Each factor level is represented by an indicator. For every reported covariate, the before and after absolute standardized mean differences use one fixed pooled original-sample standard deviation,
The before difference uses unweighted original-sample treatment-group means. The after difference uses the unit matching weights among matched units.
A list containing covariate-balance results, a network-distance summary, and the within-matched-set distance table.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") diag <- diagnose_match(m) diag$covariate_balance diag$network_summary diag$within_distance_tabledata("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") diag <- diagnose_match(m) diag$covariate_balance diag$network_summary diag$within_distance_table
Returns the original unit-level data with matched-set membership and matching weights.
matched_data(object, drop_unmatched = TRUE)matched_data(object, drop_unmatched = TRUE)
object |
A |
drop_unmatched |
If |
The unit-level data with subclass and weights.
Provides three matching methods for observational network data: dual-penalty, single-penalty, and covariate-only matching. Dual-penalty matching minimizes total covariate dissimilarity while restricting network-close pairs both between and within treatment arms in matched sets. Single-penalty matching restricts network-close pairs across treatment arms; covariate-only matching has no network-distance restriction.
netmatch(data, treat, covariates, network, method = c("dual", "single", "covariate"), kappa = 2, solver = c("highs", "auto", "gurobi", "glpk"), min_controls = 0.01, max_controls = 100, caliper = Inf, timelimit = 90, mipgap = 0.01, threads = 1, estimand = c("ATT", "ATC", "ATE"), network_type = c("auto", "adjacency", "distance"), include_solver = FALSE)netmatch(data, treat, covariates, network, method = c("dual", "single", "covariate"), kappa = 2, solver = c("highs", "auto", "gurobi", "glpk"), min_controls = 0.01, max_controls = 100, caliper = Inf, timelimit = 90, mipgap = 0.01, threads = 1, estimand = c("ATT", "ATC", "ATE"), network_type = c("auto", "adjacency", "distance"), include_solver = FALSE)
data |
Data frame with one row per unit. The names |
treat |
Name of the binary treatment column. |
covariates |
Names of the numeric or factor covariates used for matching. |
network |
Symmetric adjacency or network-distance matrix aligned with |
method |
Matching method: dual-penalty, single-penalty, or covariate-only. Default: dual-penalty ( |
kappa |
Network distance threshold used by designs with network restrictions. Default: |
solver |
Solver for dual-penalty matching. |
min_controls |
Minimum control-to-treated ratio. Default: |
max_controls |
Maximum control-to-treated ratio; use |
caliper |
Mahalanobis-distance caliper for treated-control pairs in dual-penalty matching, analogous to a propensity-score caliper; use |
timelimit |
Solver time limit in seconds. Default: |
mipgap |
Target relative MIP gap. Default: |
threads |
Requested solver threads. Default: |
estimand |
Unit matching weights used in summaries and balance diagnostics: |
network_type |
Format of |
include_solver |
If |
Dual-penalty matching requires every pair of units in a matched set to have
network distance greater than kappa. Single-penalty matching imposes
this restriction only on treated-control pairs.
Covariate dissimilarity is the square root of the Mahalanobis quadratic form, using the pooled within-treatment-group covariance matrix.
Dual-penalty matching is formulated and solved as a mixed-integer program. Covariate-only and single-penalty comparison
designs use optmatch::fullmatch().
netmatch() returns a netmatch object containing the matched data,
full-sample subclasses and unit weights, design settings, network distances, and
solver summary. The complete solver result is included only when requested.
summary() returns sample, balance, network, and solver summaries.
plot() draws the within-matched-set matching diagnostic.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch( data = sim$data, treat = "Z", covariates = c("X1", "X2", "X3"), network = sim$net_dist, method = "dual", kappa = 2, solver = "highs", estimand = "ATT" ) m summary(m)data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch( data = sim$data, treat = "Z", covariates = c("X1", "X2", "X3"), network = sim$net_dist, method = "dual", kappa = 2, solver = "highs", estimand = "ATT" ) m summary(m)
Simulated data with no treatment effect and network-dependent covariates, treatment assignment, and outcomes. The dataset was selected to illustrate how sensitivity to network dependence can change the inferential conclusion.
data(netmatch_example)data(netmatch_example)
A list containing data, a data frame with 300 rows and columns Z, X1, X2, X3, and Y; Adj, the aligned 300 by 300 undirected adjacency matrix; and net_dist, the corresponding shortest-path distances (infinite between disconnected nodes). Rows of the matrices follow the data frame's row order.
Generated with simulate_netmatch_example(seed = 17, n = 300, beta_z = 0, alpha1 = 0.9, alpha2 = 0.3, edge_prob = 4 / 299). The repository data-generation script records the construction.
data(netmatch_example) dim(netmatch_example$data)data(netmatch_example) dim(netmatch_example$data)
Compares absolute standardized mean differences before matching and across selected matching designs.
plot_covariate_balance(designs, include_before = TRUE)plot_covariate_balance(designs, include_before = TRUE)
designs |
Named list of comparable |
include_before |
Include the unmatched sample. Default: |
A ggplot object.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2) plot_covariate_balance(list("Dual-penalty" = m))data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2) plot_covariate_balance(list("Dual-penalty" = m))
Compares average treated-control Mahalanobis distance before matching and within matched sets across selected matching designs. Smaller values indicate greater covariate similarity.
plot_covariate_similarity(designs, include_before = TRUE)plot_covariate_similarity(designs, include_before = TRUE)
designs |
Named list of comparable |
include_before |
Include the unmatched sample. Default: |
A ggplot object.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2) plot_covariate_similarity(list("Dual-penalty" = m))data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2) plot_covariate_similarity(list("Dual-penalty" = m))
Plots a p-value grid or a critical sensitivity curve. Stored analysis choices, including the weighting method, are reused for conversions and unadjusted reference lines.
plot_sensitivity(x, type = NULL, alpha = 0.05, unadjusted = NULL, critical_ylim = NULL)plot_sensitivity(x, type = NULL, alpha = 0.05, unadjusted = NULL, critical_ylim = NULL)
x |
A sensitivity-grid or critical-sensitivity object. |
type |
|
alpha |
Reference or test level. Default: |
unadjusted |
Optional unadjusted p-value or test result for the p-value plot. |
critical_ylim |
Optional y-axis limits for the critical plot. Default: |
A p-value plot shows how the p-value changes with rho for
each selected value of eta. A critical plot shows the boundary value of
eta; values below the curve retain rejection at the selected alpha,
and values above it do not. If no finite boundary exists on the requested grid,
the function returns an error with the reason rather than drawing a curve.
Algebraic crossings outside the displayed range remain in the plot data but are
not critical contour points within the parameter range.
A ggplot object.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") sens <- sensitivity_grid(m, "Y", eta = c(0, 0.01, 0.05, 0.10, 0.15, 0.20), rho = seq(0, 0.5, by = 0.05)) plot_sensitivity(sens) crit <- critical_sensitivity(m, "Y") plot_sensitivity(crit)data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") sens <- sensitivity_grid(m, "Y", eta = c(0, 0.01, 0.05, 0.10, 0.15, 0.20), rho = seq(0, 0.5, by = 0.05)) plot_sensitivity(sens) crit <- critical_sensitivity(m, "Y") plot_sensitivity(crit)
Tests the sharp null that no unit's outcome is affected by any unit's treatment, including both direct effects and treatment interference. The adjusted test scales the design-based covariance bounds between matched sets using eta and rho.
RI_adjusted(match, outcome, eta = 0.03, rho = 0.10, kappa = NULL, weight_type = c("ns", "ntc"))RI_adjusted(match, outcome, eta = 0.03, rho = 0.10, kappa = NULL, weight_type = c("ns", "ntc"))
match |
A |
outcome |
Name of the numeric outcome column. |
eta |
Relative magnitude of the design-based covariance bound in |
rho |
Decay parameter in |
kappa |
Network distance threshold. |
weight_type |
Matched-set weighting. |
The test uses a weighted sum of Mann-Whitney U statistics from matched sets and
a normal approximation to obtain a two-sided p-value. The design-based covariance bound between matched sets
is scaled by eta and decays with the minimum network distance between
sets according to rho. Smaller rho gives faster decay, and
rho = 1 gives no decay. These are sensitivity parameters, not estimated
covariances. The adjusted bound must cover the cross-matched-set covariance
for the conservative inference described in the paper to apply.
The null moments assume no within-matched-set ties.
A netmatch_test object containing the test result, matched-set
details, covariance and distance matrices, analysis settings, and original
matched design.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") RI_adjusted(m, "Y", eta = 0.05, rho = 0.20)data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") RI_adjusted(m, "Y", eta = 0.05, rho = 0.20)
Tests the sharp null that no unit's outcome is affected by any unit's treatment, including both direct effects and treatment interference. The design-based test accounts for dependence using covariance bounds between matched sets.
RI_design(match, outcome, kappa = NULL, weight_type = c("ns", "ntc"))RI_design(match, outcome, kappa = NULL, weight_type = c("ns", "ntc"))
match |
A |
outcome |
Name of the numeric outcome column. |
kappa |
Network distance threshold. |
weight_type |
Matched-set weighting. |
The test uses a weighted sum of Mann-Whitney U statistics from matched sets and
a normal approximation to obtain a two-sided p-value. It uses the design-based covariance bounds without
scaling or decay for pairs of matched sets whose minimum network distance
is at most kappa. The null moments assume no within-matched-set ties.
A netmatch_test object containing the test result, matched-set
details, covariance and distance matrices, analysis settings, and original
matched design.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") RI_design(m, "Y")data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") RI_design(m, "Y")
Tests the sharp null that no unit's outcome is affected by any unit's treatment, including both direct effects and treatment interference. The unadjusted test proceeds without adjusting for covariance between matched sets.
RI_unadjusted(match, outcome, kappa = NULL, weight_type = c("ns", "ntc"))RI_unadjusted(match, outcome, kappa = NULL, weight_type = c("ns", "ntc"))
match |
A |
outcome |
Name of the numeric outcome column. |
kappa |
Network distance threshold. |
weight_type |
Matched-set weighting. |
The test uses a weighted sum of Mann-Whitney U statistics from matched sets and a normal approximation to obtain a two-sided p-value. It uses only within-matched-set variances. The null moments assume no within-matched-set ties.
A netmatch_test object containing the test result, matched-set
details, covariance and distance matrices, analysis settings, and original
matched design.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") RI_unadjusted(m, "Y")data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") RI_unadjusted(m, "Y")
Evaluates how the p-value changes over a grid of eta and
rho values. Eta scales the design-based covariance bound between matched sets. Rho controls
how that bound decays with the minimum network distance between sets: for distance d, the
multiplier is eta * rho^(d - 1).
sensitivity_grid(match, outcome, eta = seq(0, 0.10, by = 0.01), rho = seq(0, 0.50, by = 0.05), kappa = NULL, weight_type = c("ns", "ntc"))sensitivity_grid(match, outcome, eta = seq(0, 0.10, by = 0.01), rho = seq(0, 0.50, by = 0.05), kappa = NULL, weight_type = c("ns", "ntc"))
match |
A |
outcome |
Name of the numeric outcome column. |
eta |
Sensitivity-scale values in |
rho |
Sensitivity-decay values in |
kappa |
Network distance threshold. |
weight_type |
Matched-set weighting. |
The set statistic counts a treated outcome only when it is strictly greater than a control outcome. The null moments assume no tied outcomes within a matched set.
A netmatch_sensitivity object containing the p-value grid, original
matched design, and analysis settings.
data("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") sens <- sensitivity_grid(m, "Y", eta = c(0, 0.01, 0.05, 0.10, 0.15, 0.20), rho = seq(0, 0.5, by = 0.05)) sens$griddata("netmatch_example", package = "netmatchRI") sim <- netmatch_example m <- netmatch(sim$data, "Z", c("X1", "X2", "X3"), sim$net_dist, method = "dual", kappa = 2, solver = "auto") sens <- sensitivity_grid(m, "Y", eta = c(0, 0.01, 0.05, 0.10, 0.15, 0.20), rho = seq(0, 0.5, by = 0.05)) sens$grid
Generates a random network and a data frame with three covariates, a binary treatment, and an outcome. Covariates, treatment, and outcome may be correlated across connected units.
simulate_netmatch_example(seed = NULL, beta_z = 0, n = 200, alpha1 = 0.9, alpha2 = 0.1, edge_prob = 0.02)simulate_netmatch_example(seed = NULL, beta_z = 0, n = 200, alpha1 = 0.9, alpha2 = 0.1, edge_prob = 0.02)
seed |
Simulation seed. Default: |
beta_z |
Treatment effect in the outcome model. Default: |
n |
Number of units. Default: |
alpha1 |
Network-related covariance coefficient in |
alpha2 |
Unit-specific covariance coefficient in |
edge_prob |
Edge probability. Default: |
A list containing the simulated data, adjacency matrix Adj,
network-distance matrix net_dist, covariance matrix V, and the
simulation settings.
sim <- simulate_netmatch_example(seed = 2, n = 200, beta_z = 0, alpha1 = 0.9, alpha2 = 0.1, edge_prob = 0.02) dim(sim$data) table(sim$data$Z)sim <- simulate_netmatch_example(seed = 2, n = 200, beta_z = 0, alpha1 = 0.9, alpha2 = 0.1, edge_prob = 0.02) dim(sim$data) table(sim$data$Z)