EDA & Data Quality¶
Pre-fit data validation, profiling, collinearity analysis, and outlier detection/treatment.
Pre-fit data quality for MMM: validation, outlier detection + remediation, and exploratory data analysis (EDA) with plotly charts.
This package is the pre-fit sibling of mmm_framework.validation
(which diagnoses a fitted model). Everything here runs on the raw dataset
before BayesianMMM sees it.
- class mmm_framework.eda.OutlierConfig(methods=('robust_z', 'iqr', 'stl_residual', 'level_shift', 'spend_spike', 'spend_drop'), robust_z_threshold=3.5, iqr_multiplier=3.0, stl_residual_threshold=3.5, stl_period=None, rolling_window=13, level_shift_window=8, level_shift_threshold=3.25, level_shift_min_run=4, spike_ratio=5.0, spike_neighborhood=4, normalization_damage_ratio=3.0, drop_context_ratio=0.25, consensus_threshold=0.3, heavy_tail_kurtosis=2.0, heavy_tail_min_flags=5, heavy_tail_top_k=5)[source]¶
Bases:
objectThresholds for the outlier detectors.
Defaults are deliberately conservative: in MMM data, seasonal peaks and promo flights are real signal, so only points that survive the seasonally-adjusted (STL) view or an isolated-spike test should be flagged.
-
methods:
tuple[str,...] = ('robust_z', 'iqr', 'stl_residual', 'level_shift', 'spend_spike', 'spend_drop')¶
- classmethod for_sensitivity(sensitivity='default')[source]¶
Preset configs: ‘low’ flags less, ‘high’ flags more.
- Return type:
- __init__(methods=('robust_z', 'iqr', 'stl_residual', 'level_shift', 'spend_spike', 'spend_drop'), robust_z_threshold=3.5, iqr_multiplier=3.0, stl_residual_threshold=3.5, stl_period=None, rolling_window=13, level_shift_window=8, level_shift_threshold=3.25, level_shift_min_run=4, spike_ratio=5.0, spike_neighborhood=4, normalization_damage_ratio=3.0, drop_context_ratio=0.25, consensus_threshold=0.3, heavy_tail_kurtosis=2.0, heavy_tail_min_flags=5, heavy_tail_top_k=5)¶
-
methods:
- class mmm_framework.eda.DataValidationConfig(missing_warn_pct=5.0, missing_error_pct=30.0, zero_inflation_warn_pct=60.0, near_constant_cv=1e-06, scale_ratio_threshold=10000.0, min_obs_per_param=4.0)[source]¶
Bases:
objectThresholds for pre-fit dataset validation.
- __init__(missing_warn_pct=5.0, missing_error_pct=30.0, zero_inflation_warn_pct=60.0, near_constant_cv=1e-06, scale_ratio_threshold=10000.0, min_obs_per_param=4.0)¶
- class mmm_framework.eda.EDAConfig(correlation_threshold=0.8, vif_threshold=10.0, top_correlations=10, stl_robust=False, significance_level=0.05, max_series_per_chart=12)[source]¶
Bases:
objectKnobs for the EDA analyses.
- __init__(correlation_threshold=0.8, vif_threshold=10.0, top_correlations=10, stl_robust=False, significance_level=0.05, max_series_per_chart=12)¶
- class mmm_framework.eda.EDAPanel(df_wide, df_long, kpi, media, controls, unassigned, dims, date_col, freq, roles_source, duplicate_rows=0, source_path=None)[source]¶
Bases:
objectA wide panel plus role metadata, ready for EDA/validation/outliers.
- series(variable, dim_values=None)[source]¶
One variable as a Period-indexed series (a single panel slice).
- Return type:
- __init__(df_wide, df_long, kpi, media, controls, unassigned, dims, date_col, freq, roles_source, duplicate_rows=0, source_path=None)¶
- mmm_framework.eda.load_eda_panel(dataset_path, spec=None)[source]¶
Load a dataset (MFF long CSV, or wide CSV fallback) for EDA.
Duplicate (VariableName, Period, dims) rows are counted and resolved by keeping the FIRST occurrence — the count is surfaced on the panel so the validator reports it instead of silently aggregating.
- Return type:
- mmm_framework.eda.load_eda_panel_from_df(df, spec=None, source_path=None)[source]¶
Build an
EDAPanelfrom an in-memory DataFrame (the Data Studio’s staged/transformed frame) — the path-free sibling ofload_eda_panel().Same MFF-long vs wide dispatch; no disk IO so the studio can re-run EDA on every pipeline edit without writing a temp file.
- Return type:
- mmm_framework.eda.seasonal_period_for_freq(freq)[source]¶
Observations per year for STL, by frequency.
- class mmm_framework.eda.OutlierFlag(variable, period, value, expected, methods, score, kind, dims=<factory>)[source]¶
Bases:
objectOne flagged observation in one series.
- __init__(variable, period, value, expected, methods, score, kind, dims=<factory>)¶
- class mmm_framework.eda.RemediationAction(action_id, flag_ids, strategy, params, rationale, spec_change=None)[source]¶
Bases:
objectA concrete, applyable treatment for one or more flags.
- __init__(action_id, flag_ids, strategy, params, rationale, spec_change=None)¶
- class mmm_framework.eda.OutlierReport(flags, actions, config, per_variable=<factory>, dataset_path=None, dataset_mtime=None)[source]¶
Bases:
objectFull outlier-detection output: flags + recommended treatments.
-
flags:
list[OutlierFlag]¶
-
actions:
list[RemediationAction]¶
-
config:
OutlierConfig¶
- __init__(flags, actions, config, per_variable=<factory>, dataset_path=None, dataset_mtime=None)¶
-
flags:
- class mmm_framework.eda.ValidationIssue(check, severity, message, variable=None, affected=<factory>)[source]¶
Bases:
objectOne finding from a single validation check.
- __init__(check, severity, message, variable=None, affected=<factory>)¶
- class mmm_framework.eda.DataValidationReport(issues, n_periods, n_variables, config)[source]¶
Bases:
objectAll validation findings for a dataset.
-
issues:
list[ValidationIssue]¶
-
config:
DataValidationConfig¶
- __init__(issues, n_periods, n_variables, config)¶
-
issues:
- class mmm_framework.eda.DecompositionResult(variable, method, period, trend, seasonal, resid, trend_strength, seasonal_strength)[source]¶
Bases:
objectSTL (or fallback) decomposition of one series.
- __init__(variable, method, period, trend, seasonal, resid, trend_strength, seasonal_strength)¶
- class mmm_framework.eda.EDAReport(sections=<factory>, figures=<factory>)[source]¶
Bases:
objectAggregated EDA output keyed by analysis name.
sectionsholds JSON-safe dicts (one per analysis run);figuresholds the plotly figures keyed by a descriptive name — callers decide how to render/store them.- __init__(sections=<factory>, figures=<factory>)¶
- class mmm_framework.eda.OutlierDetector(panel, config=None)[source]¶
Bases:
objectRun all configured detectors over a panel’s KPI + media (+ controls).
- mmm_framework.eda.detect_outliers(panel, config=None, variables=None)[source]¶
Functional wrapper around
OutlierDetector.- Return type:
- mmm_framework.eda.recommend_treatments(panel, flags, config=None)[source]¶
Build remediation recommendations for a set of flags.
- Return type:
- mmm_framework.eda.apply_treatments(df_long, actions, flags, *, date_col='Period', kpi=None)[source]¶
Apply winsorize / dummy / exclude actions to an MFF long frame.
Returns a NEW frame; the input is not mutated.
flagsprovides the (variable, period, dims) targeting for each action’sflag_ids.- Return type:
- mmm_framework.eda.decompose_series(series, period=None, *, robust=False, rolling_window=13, variable=None)[source]¶
Decompose one series into trend / seasonal / residual.
- Return type:
Parameters¶
- seriespd.Series
Period-indexed values (NaNs are interpolated for decomposition only).
- periodint, optional
Seasonal period (e.g. 52 for weekly). When None or when fewer than two full cycles are available, falls back to a rolling-median detrend.
- robustbool
Passed to STL. Default False: with only a few seasonal cycles, statsmodels’ robust mode degenerates to near-interpolation (residual MAD ~ 0), which breaks residual-based screening. Outlier resistance comes from MAD-based z-scores on the residual instead.
- mmm_framework.eda.decomposition_summary(panel_series, period, config=None)[source]¶
Decompose several series (e.g. KPI + media) with shared settings.
- Return type:
- mmm_framework.eda.stationarity_tests(series, *, significance=0.05)[source]¶
ADF + KPSS stationarity tests with a combined verdict.
ADF null: unit root (non-stationary). KPSS null: stationary.
- class mmm_framework.eda.DataValidator(panel, config=None, spec=None)[source]¶
Bases:
objectRun every
check_*method over a panel and collect issues.
- mmm_framework.eda.validate_dataset(panel, config=None, spec=None)[source]¶
Functional wrapper around
DataValidator.- Return type:
- mmm_framework.eda.profile_panel(panel)[source]¶
Per-variable summary statistics (one row per variable).
- Return type:
- mmm_framework.eda.missingness_matrix(panel)[source]¶
Availability per (period, variable): 1 observed, 0 missing.
For panel data, a cell counts as observed when ANY slice has a value; the fraction observed is returned instead of a binary flag.
- Return type:
- mmm_framework.eda.collinearity_analysis(panel, config=None, variables=None)[source]¶
Correlation matrix + VIF + collinear clusters for media (+ controls).
Returns a dict with keys:
variables,correlation(DataFrame),vif(dict),high_vif(list),clusters(list of dicts),condition_number,top_pairs(list of dicts).