A package for imputing arbitrarily censored data
Project description
ndimpute
Unbiased statistical imputation for censored data (environmental nondetects, survival times, detection limits, and interval data).
This package implements rigorous statistical methods—Robust ROS and Parametric MLE—to handle censored data without introducing the bias inherent in simple substitution methods.
Why not just use substitution (LOD/2)?
Simple substitution (replacing values below the Limit of Detection (LOD) with LOD/2 or 0) destroys the variance of your dataset and biases mean estimates, especially for lognormal data.
| Method | Mean Error (Bias) | Standard Deviation Error |
|---|---|---|
| Substitution (LOD/2) | -15% to +20% | Severely Biased |
| ndimpute (ROS) | < 1% | < 2% |
Key Features
- Robust ROS (Regression on Order Statistics): Uses Kaplan-Meier plotting positions (handling multiple detection limits) to fit a regression line to the observed data and impute censored values based on their probability.
- Parametric Imputation: MLE-based imputation (Weibull, Lognormal, Normal) for reliability and mixed-censoring analysis.
- Interval Censoring: Handles data known only to lie within a range (e.g.,
[5, 10]) using the Turnbull Estimator. - Production-Ready: Validated against R industry standards (
NADA,survival) and fully vectorized for performance ($N > 100k$).
Installation
pip install ndimpute
For visualization support (matplotlib/seaborn):
pip install ndimpute[viz]
Quick Start
1. Simplest Case: Numeric Arrays (Recommended)
If you already have your data as numeric arrays and a boolean mask, this is the most direct way to use the library.
import numpy as np
from ndimpute import impute
# Data: 10.0, 0.5 (censored), 5.0
values = np.array([10.0, 0.5, 5.0])
is_censored = np.array([False, True, False])
# Robust ROS (Default for Left Censoring)
df = impute(values, status=is_censored, method='ros')
print(df[['original_value', 'imputed_value']])
# original_value imputed_value
# 0 10.0 10.000000
# 1 0.5 0.234... <-- Imputed below 0.5
# 2 5.0 5.000000
2. Auto-Detect from Strings
You can pass data as a list containing both numbers and strings. ndimpute will parse the < (left) and > (right) markers from the strings automatically.
from ndimpute import impute
# Mixed data: Observed numbers mixed with censored strings
data = [10.0, "<0.5", 5.0, ">100"]
# Parametric Imputation (Recommended for Mixed data)
df = impute(data, method='parametric', dist='lognormal')
When to Use Which Method
| Data Type | Censoring | Recommended Method | Why? |
|---|---|---|---|
| Environmental | Left (<LOD) |
method='ros' |
Robust to outliers; standard in environmental science. |
| Reliability | Right (>Time) |
method='parametric' |
Reliability data usually follows physical laws (Weibull). |
| Mixed | Left & Right | method='parametric' |
ROS for mixed data is biased (~14% error); MLE is consistent. |
| Interval | Interval [L, R] |
method='ros' |
Uses Turnbull estimator to handle arbitrary intervals. |
Code Example Guide:
# ❌ Don't do this - Substitution is biased!
df = impute(data, method='substitution', strategy='half')
# ✅ Do this for Environmental Data (Left Censored)
df = impute(data, method='ros')
# ✅ Do this for Reliability Data (Right Censored)
df = impute(data, method='parametric', dist='weibull')
Examples
See the examples/ directory for runnable scripts:
Statistical Methods
For deep dives into the algorithms (Kaplan-Meier, Turnbull, MLE), see STATISTICAL_METHODS.md.
Limitations
- Minimum Observations: ROS requires at least 2 uncensored observations to fit a regression line.
- Mixed Censoring Bias in ROS: While supported, using ROS for mixed censoring is less accurate than parametric methods. We recommend
method='parametric'for mixed data. - Double Censoring: The package does not currently support specific "double censoring" models (e.g., interval-censored starting time AND interval-censored ending time) often found in incubation period studies.
Validation
This package is tested against:
- R NADA Package: Matches results for single detection limits.
- R Survival Package: Matches Kaplan-Meier and Turnbull estimations.
- NADA 2: Uses improved Kaplan-Meier plotting positions for multiple detection limits (superior to legacy NADA's simple ranking).
License
MIT
Project details
Release history Release notifications | RSS feed
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 ndimpute-0.1.0.tar.gz.
File metadata
- Download URL: ndimpute-0.1.0.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.10.6 Linux/4.15.0-142-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c991db7debae7c56a9cc547a74cb66b9984889ecb816347f007c0b9dfb6fb9d8
|
|
| MD5 |
1d3d20ee20510891e72629d8905ac40e
|
|
| BLAKE2b-256 |
660129d08c55c298bcedcf886d6e4fe2860aeabc0db8764e868045298f7d2732
|
File details
Details for the file ndimpute-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ndimpute-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.7.1 CPython/3.10.6 Linux/4.15.0-142-generic
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1ed35afe6aadea3cad3d869339cea5d3fde8a4f82866aaa0b7667275fec4e743
|
|
| MD5 |
6795466a0573f3d478638824cc0cc367
|
|
| BLAKE2b-256 |
370506fd72a5b2f36870fe0b2b74c3f29e9f3830f0b3e8a66b0c218a6b4b3478
|