Semiparametric Causal Inference for Right-Censored Outcomes with Many Weak Invalid Instruments
Project description
MAWII-SURV
Semiparametric causal inference for right-censored outcomes with many weak or invalid instruments, powered by the GEL-NOW framework.
MAWII-Surv (MAny Weak and Invalid Instruments for Survival outcomes) implements GEL-NOW: Generalized Empirical Likelihood with Non-Orthogonal and Weak moments. It extends classical GEL to non-orthogonal nuisance settings and allows many weak or invalid IVs under right-censoring.
Table of Contents
- Introduction to MAWII-Surv
- Why MAWII-Surv?
- Features
- Installation
- Dependencies
- Quick Start
- API
- Arguments
- Return Values
- Notes & Tips
- Citation
- Contributing
- License
Introduction to MAWII-Surv
MAWII-Surv (MAny Weak and Invalid Instruments for Survival outcomes) is a Python package for semiparametric causal inference with right-censored outcomes in the presence of many weak or invalid instruments. The package implements the novel GEL-NOW (Generalized Empirical Likelihood with Non-Orthogonal and Weak moments, or GEL 2.0) framework, which extends classical generalized empirical likelihood to settings where nuisance functions enter non-orthogonally and where instruments may be weak or invalid.
Key features include:
-
Heteroscedasticity-based identification under an accelerated failure time (AFT) model, enabling causal effect estimation even with invalid instruments.
-
Flexible nuisance estimation using modern machine learning methods, including deep neural networks, to capture complex nonlinear structures.
-
Robust inference that explicitly accounts for additional variance from non-orthogonal nuisances, ensuring valid confidence intervals.
-
Diagnostics such as a censoring-adjusted over-identification test to assess instrument validity.
-
Applications to biobank-scale data, with built-in support for analyzing time-to-event outcomes such as disease onset.
With simulation tools, diagnostic functions, and real-data examples, MAWII-Surv provides a user-friendly platform for researchers in statistics, econometrics, epidemiology, and genetics to conduct reliable causal inference from censored survival data
Why MAWII-Surv?
- Survival + Endogeneity: G-estimation for treatment effects with right-censoring and unmeasured confounding.
- Many Weak/Invalid IVs: Robust to weak instruments and horizontal pleiotropy.
- GEL 2.0 (GEL-NOW): Empirical Likelihood (EL), Exponential Tilting (ET), and Continuous Updating (CUE) with theory for non-orthogonal nuisances.
- Modern ML Nuisances: Deep neural nets (PyTorch), Random Forests, XGBoost, plus classical linear models.
- Diagnostics: Over-identification test adapted to censoring; standard errors account for censoring-induced variance inflation.
Features
- Uncensor‐data (
mawii_noncensor) - Right‐censoring (
mawii_censor) - Multiple model backends:
- Neural networks
- Linear regression
- Random forests
- XGBoost
- Choice of Generalized Empirical Likelihood (GEL) functions:
- Empirical Tilting (ET)
- Empirical Likelihood (EL)
- Continuous Updating Estimator (CUE)
Installation
Install from PyPI:
pip install mawiisurv
Dependencies
Make sure you have the following installed (the minimal compatible versions shown):
- numpy>=1.19
- torch>=1.8
- scipy>=1.5
- scikit-learn>=0.24
- xgboost>=1.3
- numba>=0.53
If you plan to use GPU, please install a CUDA-compatible PyTorch from the official download page before installing this package.
Quick start
A runnable demo is provided below. It simulates both non-censored and right-censored data, fits the DNN + ET specification, and prints the point estimate, standard error, and the over-identification test statistic.
# demo
# pip install mawiisurv
import numpy as np
import mawiisurv
import torch
import copy
# function input
'''
Main input variables:
X: (n,p) array, covariates
Z: (n,m) array, instrumental variables
A: (n,) array, treatment
Y: (n,) array, outcome
censor_delta: (n,) array, censor indicator, 1 for uncensor and 0 for censor
h: window for local KM estimation, and default setting is 1
model_types: ['neural_network','linear_regression','random_forest','xgboost'], 4 choices of comparsion models, and default setting is ['neural_network']
rho_function_names: ['ET','EL','CUE'], GEL functions, and default setting is ['EL']
Other DNN setting:
hidden_layers=[50, 50],
learning_rate=0.0005,
weight_decay=0.0001,
batch_size=256,
dropout_rate=0,
patience=5,
epochs=1000,
validation_split=0.05,
shuffle=False,
device='cpu'
'''
# two main functions:
'''
'mawii_noncensor' for complete data
'mawii_censor' for right censor data
'''
# function output
'''
function will return a list of result, including
'beta' : estimation of treatment effect
'se' : estimated standard error
'test' : overidentification test statistics
'''
# complete data simulation
n = 10000
m = 20
p = 1
beta_0 = 0.4
device = 'cuda:0' if torch.cuda.is_available() else 'cpu'
def generate_data(n=10000, m=10, p=5, beta_0=0.4, h_2=0.2,eta_A=1,censor_rate=0.3, case='case1'):
random_coefs = np.random.normal(loc=0, scale=1, size=1000)
X = np.random.uniform(-2,2,size=(n,p))
Z = np.random.uniform(-2,2,size=(n,m))
gamma = np.sqrt(h_2 / (1.5*m)) * random_coefs[0 : m]
delta = np.sqrt(h_2 / (1.5*m)) * random_coefs[m : 2*m]
epsilon_A = np.random.normal(0, 0.4*(1-h_2), size=n)
epsilon_Y = np.random.normal(0, 0.4*(1-h_2), size=n)
alpha_case1 = np.zeros(m)
alpha_case2 = np.sqrt(h_2 / (1.5*m)) * (random_coefs[2*m : 3*m])/2
alpha_case3 = gamma / 2
Z_new = copy.deepcopy(Z)
Z_new = np.cos(Z*2)
if case == "case1":
tmp = np.random.multinomial(1, [1, 0, 0], size=m)
elif case == "case2":
tmp = np.random.multinomial(1, [0.6, 0.2, 0.2], size=m)
elif case == "case3":
tmp = np.random.multinomial(1, [0.1, 0.9, 0], size=m)
elif case == "case4":
tmp = np.random.multinomial(1, [0.1, 0, 0.9], size=m)
else:
raise ValueError("Unknown case provided.")
alpha = tmp[:, 0] * alpha_case1 + tmp[:, 1] * alpha_case2 + tmp[:, 2] * alpha_case3
U = np.random.normal(0, 0.6*(1-h_2), size=n)
A = Z_new @ gamma + U + (1 + Z @ delta)*epsilon_A
T = beta_0*A + Z_new @ alpha -U + epsilon_Y
rr = 0
while True:
C = np.random.uniform( -1+rr,5+rr, size=n)
censor_delta = np.where(T <= C, 1, 0)
if np.mean(1-censor_delta) >=censor_rate+0.03:
rr = rr + 0.1
elif np.mean(1-censor_delta)<=censor_rate-0.03:
rr = rr - 0.1
else:
break
Y = np.minimum(T,C)
return X, Z, A, Y, T, censor_delta
X, Z, A, Y, T, censor_delta= generate_data(n=10000, m=20, p=1, beta_0=0.4, h_2=0.2, eta_A=1, censor_rate=0.4, case='case1')
# uncensored data simulation
result_noncensor = mawiisurv.mawii_noncensor(X, Z, A, T,
model_types=['neural_network'], # options: ['neural_network','linear_regression','random_forest','xgboost'],
rho_function_names=['ET'], # options: ['ET','EL','CUE'],
device = device)
print(f"DNN+ET BETA: {result_noncensor['neural_network']['ET']['beta']:.3f}")
print(f"DNN+ET SE: {result_noncensor['neural_network']['ET']['se']:.3f}")
print(f"DNN+ET over-identification test: {result_noncensor['neural_network']['ET']['test']:.3f}")
# right-censor data simulation
result_censor = mawiisurv.mawii_censor(X, Z, A, Y, censor_delta, h = 4,
model_types=['neural_network'], # options: ['neural_network','linear_regression','random_forest','xgboost'],
rho_function_names=['ET'], # options: ['ET','EL','CUE'],
device = device)
print(f"DNN+ET BETA: {result_censor['neural_network']['ET']['beta']:.3f}")
print(f"DNN+ET SE: {result_censor['neural_network']['ET']['se']:.3f}")
print(f"DNN+ET over-identification test: {result_censor['neural_network']['ET']['test']:.3f}")
API
mawii_noncensor(
X, Z, A, Y,
model_types=['neural_network'],
rho_function_names=['ET'],
hidden_layers=[50, 50],
learning_rate=0.0005,
weight_decay=0.0001,
batch_size=256,
dropout_rate=0,
patience=5,
epochs=100,
validation_split=0.05,
shuffle=False,
device='cpu',
) -> dict
mawii_censor(
X, Z, A, Y, censor_delta, h=1,
model_types=['neural_network'],
rho_function_names=['ET'],
hidden_layers=[50, 50],
learning_rate=0.0005,
weight_decay=0.0001,
batch_size=256,
dropout_rate=0,
patience=5,
epochs=100,
validation_split=0.05,
shuffle=False,
device='cpu',
) -> dict
Arguments
-
X: array of shape n by p, baseline covariates
-
Z: array of shape n by m, instrumental variables
-
A: array of shape n, treatment
-
Y: array of shape n, outcome
-
censor_delta: array of shape n, 1 uncensored and 0 censored, only for mawii_censor
-
h: scalar, window for local Kaplan–Meier in censoring adjustment
-
model_types: list of model backends, choose from neural_network, linear_regression, random_forest, xgboost
-
rho_function_names: list of GEL score types, choose from ET, EL, CUE
-
device: cpu or cuda device string such as cuda:0
Return values:
{
'neural_network': {
'ET': {
'beta': float, # point estimate
'se': float, # standard error
'test': float # overidentification test statistic
},
'EL': {...},
'CUE': {...}
},
'linear_regression': {...},
...
}
Notes
-
We generally recommend ET or EL over CUE under weak identification.
-
Deep NNs tend to be most robust for complex nonlinear nuisances; RF/XGB are strong baselines in moderate dimensions.
-
Under censoring, standard errors include an extra variance component due to estimating the censoring distribution.
Citation:
If you use MAWII-Surv, please cite:
Bu Q., Su W., Zhao X., Liu Z. (2025).
Semiparametric Causal Inference for Right-Censored Outcomes with Many Weak Invalid Instruments.
(manuscript)
BibTeX:
@misc{mawiisurv2025,
title = {Semiparametric Causal Inference for Right-Censored Outcomes with Many Weak Invalid Instruments},
author = {Bu, Qiushi and Su, Wen and Zhao, Xingqiu and Liu, Zhonghua},
year = {2025},
note = {Python package: MAWII-Surv},
howpublished = {\url{https://pypi.org/project/mawiisurv/}}
}
Contributing
Contributions are welcome!
Please use Issues for bug reports and pull requests for code contributions.
License
MIT License — see LICENSE for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mawiisurv-0.6.0.tar.gz.
File metadata
- Download URL: mawiisurv-0.6.0.tar.gz
- Upload date:
- Size: 6.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a5070fcf6dbad00fab038a49b7865fd60c6492081ba21bfa769eed6f12ff9fda
|
|
| MD5 |
8751bca7993e2c4ba49f3ad13ffe3b2e
|
|
| BLAKE2b-256 |
115984f8569b20c30a2dadbfffc8acec499281766c8df26c4bcb25727b3e65e1
|
File details
Details for the file mawiisurv-0.6.0-py3-none-any.whl.
File metadata
- Download URL: mawiisurv-0.6.0-py3-none-any.whl
- Upload date:
- Size: 6.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b301fc4d461214765fae2de326e97663bb8471564ced62713eeabf4192bc206
|
|
| MD5 |
1992dd64b9e2ce3d57fa5ea521d5cfb8
|
|
| BLAKE2b-256 |
e2010786a0264204397d74af14e429232dca775c6ea28b62840c2d66d10eb31c
|