Skip to main content

TSGap

DOI

A Python library for simulating realistic missingness in time-series data for imputation benchmarking.

TSGap separates mechanisms (why data is missing: MCAR, MAR, MNAR) from patterns (how data is missing: pointwise, block, monotone, decay, markov, Gilbert-Elliott). Most patterns can be combined with any mechanism, making it easy to create controlled missing-data scenarios for evaluating imputation methods. gilbert_elliott is MCAR-only because it models an independent burst-loss channel rather than value- or driver-dependent missingness.

Complete data (left) vs. five mechanism+pattern combinations at 20% missing rate.

Features

  • MCAR, MAR, and MNAR missingness mechanisms
  • Pointwise, block, monotone, temporal decay, Markov-chain, and Gilbert-Elliott patterns
  • 2D (time, features) and 3D (samples, time, features) arrays
  • Exact or calibrated missing-rate control
  • Weighted multi-driver MAR
  • Reproducible masks with NumPy random seeds
  • Existing NaNs and target dimensions preserved across patterns

Installation

pip install tsgap

For development:

git clone https://github.com/feruzoripov/tsgap.git
cd tsgap
pip install -e ".[dev]"

Requires Python 3.9 or newer and NumPy 1.19 or newer.

Quick Start

import numpy as np
from tsgap import simulate_missingness

X = np.random.default_rng(42).standard_normal((1000, 6))

# MCAR: 15% scattered missing values
X_miss, mask = simulate_missingness(X, "mcar", 0.15, seed=42)

# MAR: missingness driven by dimension 0 and arranged in blocks
X_miss, mask = simulate_missingness(
    X, "mar", 0.25, seed=42,
    pattern="block", driver_dims=[0], block_len=10
)

# Scale block length to the sequence length for long series
# The default block pattern uses block_len=10 and block_density=1.0.
# block_frac is recommended
# for long wearable-style series where fixed 10-sample blocks are too short.
X_miss, mask = simulate_missingness(
    X, "mcar", 0.20, seed=42,
    pattern="block", block_frac=0.01
)

# Sample each block length between 1% and 5% of the time axis
X_miss, mask = simulate_missingness(
    X, "mcar", 0.20, seed=42,
    pattern="block", block_frac=(0.01, 0.05)
)

# MNAR: extreme values missing with monotone dropout
X_miss, mask = simulate_missingness(
    X, "mnar", 0.20, seed=42,
    pattern="monotone", mnar_mode="extreme"
)

# Gilbert-Elliott: bursty packet-loss with leaky good/bad periods.
# Burst length is controlled by `persist` (not block_frac): higher persist
# means longer bursts. `bad_loss` < 1 lets some values through during a bad
# period, and `good_loss` > 0 drops the occasional value during a good period.
X_miss, mask = simulate_missingness(
    X, "mcar", 0.20, seed=42,
    pattern="gilbert_elliott", persist=0.9,
    bad_loss=0.8, good_loss=0.02
)

print(f"Actual missing rate: {(~mask).mean():.4f}")

The returned mask uses:

mask == True  -> observed
mask == False -> missing

Documentation

Example Use Cases

  • Random telemetry loss in sensor networks
  • Activity-dependent dropout in wearable devices
  • Participant dropout in longitudinal or clinical studies
  • Gradual signal loss from sensor degradation
  • Intermittent connectivity failures with bursty missingness

Evaluation Workflow

import numpy as np
from tsgap import simulate_missingness

X = np.random.default_rng(42).standard_normal((1000, 6))
X_miss, mask = simulate_missingness(X, "mar", 0.20, seed=42, driver_dims=[0])

X_imputed = your_imputation_method(X_miss)
missing_idx = ~mask

rmse = np.sqrt(np.mean((X[missing_idx] - X_imputed[missing_idx]) ** 2))
mae = np.mean(np.abs(X[missing_idx] - X_imputed[missing_idx]))

See docs/benchmarking.md for a complete baseline workflow.

The repository also includes a runnable benchmark example:

python examples/benchmark_imputation.py

Testing

pytest tsgap/tests/ -v

Citation

@software{tsgap,
  author = {Oripov, Feruz and Korchagina, Kseniia and Bonsu, Enock Adu and Bilgin, Ali and Aras, Shravan},
  title = {TSGap: A Python Library for Composable Time-Series Missingness Simulation},
  year = {2026},
  version = {0.7.0},
  doi = {10.5281/zenodo.21365453},
  url = {https://github.com/feruzoripov/tsgap}
}

License

MIT

Metadata

Release files for tsgap 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tsgap 0.7.0
File Size Uploaded
tsgap-0.7.0.tar.gz 564.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tsgap 0.7.0
File Interpreter ABI Platform
tsgap-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 592.4 kB

Release files / tsgap-0.7.0.tar.gz

Download URL tsgap-0.7.0.tar.gz
Size 564.6 kB
Tags Source
SHA-256 checksum
How to use checksums
d0a7aa58ced192849f35f40fa20e85015b18f9574e02f633994271caffbee2c4
BLAKE2b-256 checksum
How to use checksums
6d989e9fa66818d11006d5c48c6877b4ad49fff1a4a736d928bd8f147f28b05e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release files / tsgap-0.7.0-py3-none-any.whl

Download URL tsgap-0.7.0-py3-none-any.whl
Size 27.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e424bf98cbe8675c3867f2850364eec4c098412eb90f7f852043020488919154
BLAKE2b-256 checksum
How to use checksums
97672ba71d12819f337910209aba7226ed8972482f1d695e3ad5de6928e95c1e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.3

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page