Mathematical Details
Installation | Core concepts | Mechanisms | Patterns | Mathematical details | Benchmarking workflow | API reference
This page describes how TSGap turns a complete time-series array into
(X_missing, mask). The goal is to make the probability calculations and mask
construction explicit enough for reproducible benchmarking.
TSGap separates missingness into two steps:
A mechanism decides why entries are selected for missingness.
A pattern rearranges those selected entries in time.

The returned mask uses:
mask == True -> observed
mask == False -> missing
Intuition: A Plain-Language Walkthrough
If you are new to the math, start here. This section explains every idea and symbol in everyday language before the formal definitions below.
The big picture
Imagine a spreadsheet of sensor readings — rows are moments in time, columns are different measurements (heart rate, temperature, and so on). TSGap’s job is to poke “holes” in this spreadsheet on purpose: deleting some values so you can later test whether an imputation program can guess them back correctly.
Real data does not lose values randomly, so TSGap pokes holes in realistic ways. That is what all the math is for. It happens in two steps: first decide which values disappear (the mechanism), then decide how the gaps are shaped over time (the pattern).
The basic ingredients
X(your data). The spreadsheet. Shape(T, D)is one subject:Trows (timesteps) andDcolumns (features). Shape(N, T, D)isNsubjects stacked together. Two shapes exist because sometimes you study one patient over time, sometimes many patients at once.r(the missing rate). The fraction of values to delete.r = 0.15means “delete 15%.” It is forced between 0 and 1 — you cannot delete 150% of your data.E(the eligible set). The cells we are allowed to delete. We exclude cells that are already blank (you cannot delete a blank) and columns you asked to leave alone. We need this so we only measure holes we made, not ones that were already there.mask(the answer key). A true/false grid the same size as the data.True= still here,False= we deleted it. It tells you exactly which cells you poked out so you can score an imputation method fairly.
Step 1: Which values to delete (the mechanism)
There are three styles, each a different reason data goes missing.
MCAR — totally random. Every eligible cell has an equal chance, like drawing
names from a hat. We compute how many to delete, m = round(r * |E|), then draw
exactly that many. Here |E| is the number of eligible cells. This is exact.
MAR — missing because of another measurement. Example: a heart-rate sensor fails more during hard exercise. The heart rate goes missing, but the cause is activity level (a column we can still see).
y_t(driver signal). We combine one or more “driver” columns into a single number per timestep. With multiple drivers we use weightsw_k(say activity 80%, temperature 20%). The normalized weightsw̃_kare just the weights divided by their total so they add up to 1 — this keeps the scale sensible no matter what numbers you type.s_t(normalized signal). We rescaleyto have average 0 and spread 1 usings = (y - mean) / std. Themeancenters it; thestd(standard deviation, a measure of spread) puts everything on a common scale. Without this, a heart rate (~70) and a temperature (~37) would not be comparable.The sigmoid
σ. An S-shaped function that squishes any number into a probability between 0 and 1. Big positive input → near 1 (almost surely delete); big negative → near 0 (almost surely keep); 0 → 0.5 (coin flip).α(strength). How steep the S is — how strongly the driver matters. Bigα= the driver dramatically changes the odds; smallα= it barely matters.β(offset). A knob that slides the S left or right to control the overall deletion rate. You do not set it by hand; TSGap finds it automatically (see calibration below).base_rate(floor). A minimum deletion chance so even “safe” values are not fully protected. It is capped at half the target rate so it never contradicts a lowr.
MNAR — missing because of its own value. Example: a thermometer maxes out
and cannot record extreme heat, so the reading vanishes because it was too
high. We z-score the value itself (z = (X - mean) / std) and pick a score:
z targets high values, -z targets low values, |z| targets both extremes.
Then the same sigmoid turns the score into a probability.
Calibration: finding β automatically
You want exactly 20% missing, but the sigmoid gives whatever it gives. TSGap
plays “guess the number” (binary search) on β: guess a value, check the
resulting rate, nudge up if too low or down if too high, and keep halving the
range until it is close. This works because raising β always raises the rate,
so the search always closes in.
Sampling: flipping the coins
Every eligible cell now has a probability p. We draw a random number
u between 0 and 1 and delete the cell if u ≤ p. A bigger p means a bigger
“delete zone,” so it is more likely to go. Because this is coin-flipping, MAR and
MNAR hit the target rate approximately; MCAR is exact because it draws a fixed
count instead.
Step 2: How the gaps are shaped in time (the pattern)
Step 1 chose which cells and how many. Step 2 rearranges them into realistic shapes while keeping the same total count.
Pointwise. Do nothing; holes stay scattered like sprinkles.
Block. Group holes into solid chunks (a sensor offline for 10 minutes).
block_densitysets how many holes go into chunks versus staying scattered;block_lensets chunk length in steps;block_fracsets it as a fraction of total time (so it scales to long recordings), and a range makes chunk lengths vary.Monotone. Once it breaks, it stays broken (a patient drops out for good). The dropout time
τ = T - (missing count for that series)is the moment a series goes dark forever. Series the mechanism hit harder go dark earlier.Decay. Holes grow more common over time (a dying battery). A time weight
w(t) = σ(decay_rate * (t_norm - decay_center))makes later steps more likely to be chosen.decay_centeris where failure crosses 50% (0.7 = last 30%);decay_ratecontrols how sharp the drop-off is.Markov. Flickering on and off (a loose connection).
persistis the chance a broken sensor stays broken next step (high = long outages). The onset probability (chance a working sensor breaks) is solved automatically so the long-run average matches the target rate.Gilbert-Elliott. A more realistic version of flickering (bursty packet loss). The sensor alternates between “good” and “bad” periods, but a bad period only loses data most of the time (
bad_loss), and a good period can still drop the occasional value (good_loss). This makes bursts look ragged rather than perfectly on/off.
Step 3: Finishing up
Cells marked False become NaN in the output, pre-existing blanks stay blank,
and using the same seed always reproduces the exact same holes. The formal
definitions of everything above follow in the rest of this page.
Notation
Let the input array be either:
Xwith shape(T, D)for one multivariate time series, orXwith shape(N, T, D)forNsamples or subjects.
Here T is the number of timesteps and D is the number of features.
Let r be the requested missing_rate. TSGap clips it to [0, 1].
Let E be the eligible set of entries that may be artificially masked:
E = entries that are not already NaN and belong to the target dimensions
Pre-existing NaNs are never converted back to observed values. They are marked as missing in the returned mask but are excluded from the artificial missingness rate calculation.
The achieved artificial missing rate over eligible entries is:
Overall Algorithm
For a call such as:
X_missing, mask = simulate_missingness(
X,
mechanism="mar",
missing_rate=0.25,
pattern="block",
seed=42,
driver_dims=[0],
block_frac=(0.02, 0.10),
)
TSGap performs:
Create a NumPy random generator from
seed.Identify pre-existing NaNs.
Build the eligible set
Efromtargetand non-NaN entries.Generate a mechanism mask.
Apply the temporal pattern to the mechanism mask.
Force pre-existing NaNs to remain missing.
Return
X_missing, where allmask == Falseentries are set tonp.nan.
MCAR
MCAR means Missing Completely At Random. The data values do not affect the probability of being masked.
TSGap samples exactly:
eligible entries without replacement. If U is the sampled subset of E, then:
This gives exact missing-count control up to rounding. For example, if |E| = 1000 and r = 0.15, TSGap masks exactly round(1000 * 0.15) = 150 eligible
entries before any temporal pattern is applied.
MAR
MAR means Missing At Random. Missingness depends on observed driver variables, not directly on the value being masked.
Driver Signal
For 2D data, if driver_dims=[d_1, ..., d_K], the driver signal at timestep
t is either the average driver value:
or, when driver_weights=[w_1, ..., w_K] is provided, a weighted driver value:
where weights are normalized:
For 3D data, the same calculation is performed separately for each sample:
Normalization
For 2D data, the driver signal is normalized over time:
For 3D data, normalization is performed per sample:
If the standard deviation is numerically zero, TSGap uses a zero normalized signal to avoid division by zero.
If direction="negative", TSGap flips the signal:
This means:
direction="positive": larger driver values imply larger missingness probability.direction="negative": smaller driver values imply larger missingness probability.
Logistic Probability
TSGap converts the normalized driver signal into a missingness probability with a sigmoid function:
where:
alpha is strength, and beta is an offset calibrated by binary search.
For MAR, TSGap also applies a probability floor:
To prevent the floor from conflicting with low target rates, base_rate is
first capped at half the requested rate:
The probability is broadcast from each timestep to the eligible target features at that timestep. Non-eligible entries receive probability zero.

Offset Calibration
The offset beta is chosen so the mean missingness probability over eligible
entries matches the requested rate:
TSGap uses binary search because increasing beta monotonically increases the
probabilities. The search range is expanded when necessary and clipped for
numerical stability.
Sampling
After probabilities are computed, each eligible entry is sampled independently:
Because MAR samples Bernoulli outcomes, the achieved rate is approximate and can vary more on small arrays.
MNAR
MNAR means Missing Not At Random. Missingness depends on the value being masked.
Value Normalization
For 2D data, each feature is normalized over time:
For 3D data, each sample-feature series is normalized separately:
If a standard deviation is numerically zero, TSGap uses 1.0 as the denominator
to avoid division by zero.
MNAR Score
The score depends on mnar_mode:
So:
"high"makes high values more likely to be missing."low"makes low values more likely to be missing."extreme"makes values far from the mean more likely to be missing.
Logistic Probability And Sampling
MNAR uses the same calibrated sigmoid and offset structure as MAR, but without
the base_rate probability floor:
The offset beta is calibrated so:
Then each eligible entry is sampled independently:
As with MAR, the achieved rate is approximate because sampling is Bernoulli.
Pointwise Pattern
The pointwise pattern is the default. It does not rearrange the mechanism mask.
If the mechanism selected entries:
t = 1, 4, 9, 11, ...
the pointwise pattern leaves them as scattered missing points. Therefore:
MCAR + pointwise gives uniformly scattered missing values.
MAR + pointwise gives scattered missing values whose probabilities depend on driver variables.
MNAR + pointwise gives scattered missing values whose probabilities depend on the values themselves.
Block Pattern
The block pattern converts some or all mechanism-selected missingness into contiguous runs along the time axis.
Let:
be the number of missing entries selected by the mechanism.
The block_density parameter controls how much of this missingness is allocated
to blocks:
TSGap keeps M_point scattered missing entries and restores the rest before
adding contiguous blocks.
Block Length
By default, blocks use an absolute sample length:
block_len = 10
For long time series, block_frac is often more meaningful. A scalar
block_frac=f gives:
clipped to the range [1, T].
For example, with T = 30000 and block_frac = 0.02:
If block_frac=(f_min, f_max), each block samples a new fraction:
Block Placement
For each block, TSGap:
Selects an eligible sample-feature series.
Samples a start time uniformly:
Masks eligible observed entries in:
Truncates the final block if needed to avoid overshooting the requested block missing count.
With enough eligible observed positions, this preserves the mechanism’s missing count while changing the temporal shape from scattered points into blocks.
Monotone Pattern
The monotone pattern models dropout. Once a series becomes missing, later eligible timesteps remain missing.
For each sample-feature series (n, d), TSGap first computes the missing
density assigned by the mechanism:
The global missing budget is then allocated across series in proportion to these densities:
The dropout time is:
All eligible entries from tau onward are masked:
Non-eligible entries in the tail (pre-existing NaNs or non-target dimensions) are left untouched by the pattern. This preserves the mechanism’s influence: series with higher mechanism-assigned missing density drop out earlier.
Temporal Decay Pattern
The temporal decay pattern shifts missingness toward later timesteps.
First, TSGap creates normalized time values:
Then it computes sigmoid time weights:
with a small floor:
The number of missing entries selected by the mechanism is preserved:
TSGap samples M eligible entries without replacement with probability
proportional to the time weight:
This means later timesteps are more likely to become missing, while earlier timesteps can still be selected.
Markov Pattern
The Markov pattern creates bursty temporal dependence. Each sample-feature series is modeled with two states:
observed
missing
Let:
be the target missing fraction after the mechanism step.
The persist parameter is:
It controls how likely a missing burst is to continue.
TSGap computes the onset probability from the stationary distribution:
Solving for p_onset gives:
Then each sample-feature series is simulated over time:
Higher persist values create longer missing bursts. Lower values create more
rapid flickering.
The Markov pattern controls the target rate in expectation, not as an exact
count. The final realized rate can differ from r, especially when T, N, or
D is small, because each sample-feature series is generated stochastically.
Gilbert-Elliott Pattern
The Gilbert-Elliott pattern generalizes the Markov pattern into a two-state hidden Markov model, the classic burst-loss model from telecommunications.
Each sample-feature series has a hidden state that is either good or bad. The state evolves as a 2-state Markov chain:
Unlike the Markov pattern, the state does not directly determine missingness. Instead, within each state a value is missing with a state-dependent probability:
where h is bad_loss and k is good_loss, with 0 <= k < h <= 1. The
Markov pattern is the special case h = 1, k = 0.
This makes Gilbert-Elliott useful for channel-like dropout. A bad state means “high loss”, not necessarily “everything missing”; a good state means “low loss”, not necessarily “everything observed”.
Rate Calibration
Let rho be the target missing fraction over eligible entries:
The stationary probability of being in the bad state is:
The long-run missing rate combines both states:
Solving for the required bad-state occupancy:
For partial missing rates, the requested rate must be feasible for the chosen state-loss probabilities:
TSGap raises ValueError when this condition is not met. This avoids silently
returning a mask whose missing rate is constrained by good_loss or bad_loss
rather than by the requested target. When the target is feasible, TSGap recovers
the onset probability the same way as the Markov pattern:
The feasible-rate condition has two practical consequences:
If
rho < good_loss, even an always-good channel would lose too many values.If
rho >= bad_loss, even an always-bad channel would not lose enough values for a partial-rate stochastic simulation.
The special edge case rho = 1 is handled directly by masking every eligible
entry.
Simulation
For each eligible sample-feature series, TSGap:
Initializes the hidden state as bad with probability
pi_bad.At each timestep, if the entry is eligible, marks it missing with probability
hin the bad state orkin the good state.Transitions the hidden state using
p_persist(from bad) orp_onset(from good).
The hidden state continues to evolve across non-eligible timesteps, so bursts span small ineligible gaps naturally. Because emission is stochastic, the achieved rate is approximate, as with the Markov pattern.
The expected missing rate is:
but the realized rate is:
and can vary around rho because both hidden states and state-dependent losses
are sampled.
Gilbert-Elliott currently supports only MCAR. It uses the MCAR mechanism mask to
set the missingness budget over eligible entries, then samples new locations
from the hidden-state burst process. Use the markov pattern if you need a
bursty temporal process that composes with MAR or MNAR.
Gilbert-Elliott Parameter Edge Cases
TSGap validates the parameters before simulation:
For partial missing rates:
If rho = 0, the mechanism step produces no new missing values, so the pattern
returns without adding artificial missingness. If rho = 1, every eligible
entry is masked.
Examples:
Configuration |
Behavior |
|---|---|
|
Clean on/off bursts, similar to |
|
Bad periods are leaky; some values survive |
|
Good periods still have occasional dropouts |
|
Infeasible; raises |
|
Infeasible; raises |
Reproducibility
All randomness flows through NumPy’s Generator API:
rng = np.random.default_rng(seed)
Passing the same seed and the same configuration gives the same mask.
Practical Interpretation
The mechanism controls the probability landscape:
MCAR: every eligible point starts equally likely.
MAR: probability follows observed driver variables.
MNAR: probability follows the value being masked.
The pattern controls the temporal shape:
pointwise: leave selected entries scattered.
block: group selected entries into contiguous dropout episodes.
monotone: move missingness into tail dropout.
decay: shift missingness toward later timesteps.
markov: create bursty on/off missingness.
gilbert-elliott: create ragged bursts with leaky good and bad periods.
Together, these two axes let users test whether an imputation method is robust to both the statistical cause and temporal structure of missing data.