preprocessing.outlier.outlier_mask

preprocessing.outlier.outlier_mask(
    data,
    *,
    contamination=0.1,
    random_state=1234,
    columns=None,
)

Boolean outlier mask, True where Isolation Forest flags a cell.

This is the module’s single detector primitive: every other outlier view derives from it (labels np.where(mask[col], -1, 1), counts mask.sum(), values data.where(mask)). One :class:IsolationForest estimator is fitted per column, independently, in column order, with a fresh estimator per column so flagging one column never influences another.

Pure: data is never modified.

Parameters

Name Type Description Default
data pd.DataFrame The input dataset. required
contamination float The (estimated) proportion of outliers per fitted column. 0.1
random_state int Random seed for reproducibility. Default is 1234. 1234
columns Sequence[str] | None Columns to fit. None (default) fits every column of data. When given, only the named columns are fitted; the returned mask is still full-width (same index and columns as data), with False everywhere outside columns. None

Returns

Name Type Description
pd.DataFrame pd.DataFrame: A boolean frame with the same index and columns as data. True marks a cell Isolation Forest flagged as an outlier. Columns not selected via columns are all-False.

Raises

Name Type Description
TypeError If data is not a :class:pandas.DataFrame.
ValueError If data is empty or has no columns.
KeyError If columns names a column not present in data.

Examples

import numpy as np
import pandas as pd

from spotforecast2_safe.preprocessing.outlier import outlier_mask

rng = np.random.default_rng(0)
# Column "a" has two injected outliers, column "b" has none.
data = pd.DataFrame({
    "a": np.concatenate([rng.normal(10.0, 1.0, 50), [1000.0, -1000.0]]),
    "b": rng.normal(0.0, 1.0, 52),
})

mask = outlier_mask(data, contamination=0.05, random_state=42)
assert mask.shape == data.shape
assert list(mask.columns) == list(data.columns)
assert mask["a"].sum() >= 2
print(f"Flagged in 'a': {int(mask['a'].sum())}, in 'b': {int(mask['b'].sum())}")

# columns= restricts fitting; the mask stays full-width.
mask_a_only = outlier_mask(data, contamination=0.05, random_state=42, columns=["a"])
assert mask_a_only.shape == data.shape
assert not mask_a_only["b"].any()
assert mask_a_only["a"].equals(mask["a"])
Flagged in 'a': 3, in 'b': 3