GeoSC Documentation

GeoSC is a Python toolkit and command-line interface (CLI) for designing and analysing geo-level marketing experiments with SparseSC synthetic control. It supports three operational stages: power analysis, donor screening, and inference. The stages share an outcome panel and design decisions, but their artefacts are not automatically passed from one stage to the next.

Use GeoSC only when the treated geography, eligible donor pool, treatment timing, outcome definition, and contamination risks can be defended. A successful command or a small p-value does not establish those conditions.

Choose a route

Repo-local example assets such as data-config/ only work from a source checkout. Built distributions install the Python package and CLI but do not ship data-config/, recipes/, or shapemap/.

Subsections of GeoSC Documentation

Explanation

Subsections of Explanation

Causal Estimand and Identification

GeoSC reports an unscaled average post-period treated-minus-counterfactual difference. Calling it causal requires more than estimator completion.

For treated set \(\mathcal{T}\) and measured post periods \(\mathcal{P}\), the target can be written conceptually as

$$ \tau = \frac{1}{|\mathcal{P}|} \sum_{t \in \mathcal{P}} \left(\bar{Y}_{\mathcal{T}t}(1)-\bar{Y}_{\mathcal{T}t}(0)\right). $$

The observed treated outcome supplies \(\bar{Y}(1)\). SparseSC estimates the unobserved \(\bar{Y}(0)\) from eligible donor outcomes.

A causal interpretation needs a stable outcome definition; treatment timing and assignment measured correctly; donors unaffected by treatment; no uncontrolled geography-specific shock aligned with launch; adequate pre-period support for the counterfactual; and an estimand whose geography and period match the business question. These conditions are design arguments, not outputs of the optimiser.

GeoSC’s parallel-trends diagnostic can be required as an operational gate, but passing it does not prove exchangeability. The interference screen is advisory and has no exposure model. Power addresses detection under a simulated DGP, not identification. State each evidence source separately.

Cooldown, Seasonality, and Anticipation

Cooldown excludes observed periods between launch and measurement. It is useful when response builds gradually, attribution matures, or short-term launch noise is outside the estimand. It also removes data and can reduce power.

GeoSC counts observed periods. With daily data, cooldown_periods: 7 excludes seven observed days; missing dates make that different from seven calendar days. The resolved analysis window is persisted in validation and result artefacts.

Cooldown does not fix anticipation. If customers or media respond before the declared launch, the pre-period is contaminated. Move the intervention boundary only when the behavioural timing supports it, not to improve fit.

Power’s native CLI does not apply the inference cooldown resolver. Set the power split and simulated duration to represent the actual measurement design, and document the translation.

Historical data should cover comparable seasonal conditions. The factor VAR(1) DGP has no explicit day-of-week, holiday, or campaign-season terms. A long but non-comparable history can be worse than a shorter seasonally relevant window; use pre-specified sensitivity checks.

Design Rejection

GeoSC should reject or defer a design when the requested causal statement is not supported. At minimum, stop when:

  • treatment, outcome, geography, or measurement window is unresolved;
  • treatment exposure cannot be separated from donors;
  • the panel cannot satisfy the explicit data contract;
  • no substantively eligible donor pool remains;
  • pre-period fit is materially inadequate or dependent on an implausible donor;
  • placebo support cannot resolve the pre-specified alpha;
  • power is inadequate for the commercially plausible effect range;
  • simulation failures or DGP sensitivity make MDE unstable;
  • required assumption checks fail or inference status is failed;
  • conclusions reverse under small, equally defensible specifications.

Some failures can be repaired by changing geography, outcome, history, duration, or eligibility. That creates a new design and requires a new power assessment. If no repair is defensible before treatment, document the experiment as descriptive or infeasible. A forced estimate is not a more helpful answer.

Donor Quality

Donor quality has two distinct meanings in GeoSC.

The donor stage measures pairwise pre-period similarity. Correlation captures co-movement; RMSE and MAPE capture level error; normalised DTW captures temporal shape. Composite scores are relative within each treated geography and support screening. They do not estimate final counterfactual weights.

Inference measures joint synthetic-control fit. Several individually modest donors can combine well, while a highly correlated donor can receive little weight. Review fitted pre-period error and the SparseSC weight distribution.

Strong screening scores do not establish donor exchangeability. Eligibility also requires no treatment exposure, comparable outcome measurement, and no post-launch shock that differentially moves the donor. Conversely, poor overlap, incomplete metrics, concentrated recommendation weights, or weak joint pre-fit are direct reasons to reconsider the design.

Donor selection must be outcome-blind with respect to the measured post period. Changing the pool after seeing lift invalidates ordinary interpretation unless the search and multiplicity are explicitly modelled.

Frequently Asked Questions

Is a donor the same as a control?

A donor is an eligible control geography that can contribute to a synthetic counterfactual. In code, power calls all non-treatment units controls. Preserve the eligibility distinction in design documentation.

Do donor recommendations flow into inference?

No. The pipeline runs stages independently. Filter and version the panel if the donor screen changes the eligible universe, then rerun affected stages.

Is GeoSC power simulation-based?

Yes. It estimates a factor-VAR DGP from the pre-period, simulates post-periods, injects effects, calls SparseSC, and counts p-values below alpha. It is more computationally intensive than a closed-form MDE but not automatically more accurate.

Does power use the complete inference workflow?

No. It uses the SparseSC estimator and detection rule inside simulation but has a narrower configuration and does not run inference data policies, cooldown, assumption gates, or result processing.

Why can estimated power decrease at a larger effect or duration?

Finite Monte Carlo estimates can fluctuate. Large reversals can also indicate failures, coarse placebo support, a weak DGP, or specification sensitivity. Increase simulations and investigate; do not label an empirical rolling-window diagnostic a theoretical monotonic power curve.

What does MDE mean here?

For a duration, it is the smallest valid effect on the tested grid reaching configured target_power. It is not expected campaign lift and is not interpolated.

How is a relative effect injected?

GeoSC multiplies one pooled mean across treated units and all pre-periods by the relative effect, then adds the same absolute path to each treated unit.

What does valid mean in power output?

At least one simulation succeeded and failure rate did not exceed the threshold. It says nothing about DGP plausibility or causal identification.

What is the top-level inference p-value?

It is a two-sided, add-one-corrected in-space placebo p-value for the absolute average post-period effect. It is not a post/pre MSPE-ratio p-value.

Can a small donor pool produce significance?

Only at the resolution allowed by its effective placebo count. The smallest step is 1 / (n_placebos + 1) under the implemented calculation.

Does status: ok prove the campaign caused lift?

No. It means the software result contract completed. Identification depends on eligibility, isolation, measurement, timing, pre-fit, and sensitivity evidence.

Does GeoSC calculate ROI or iROAS?

No. Combine a defensible incremental outcome with campaign cost and the correct commercial value or margin definition downstream.

Does GeoSC support GPU inference?

No. Optional CuPy work is limited to supported unseeded power DGP paths. Seeded power and main SparseSC inference are CPU-based.

Method Comparisons

Compare estimands and decision rules before comparing numbers.

Method family Counterfactual Typical uncertainty Main diagnostic focus
GeoSC SparseSC-weighted individual donors In-space placebo effects and intervals Joint pre-fit, donor weights, placebo support, simulation diagnostics
Google TBR/GBR and matched-market workflows Time-based regression on aggregated treatment and control signals Model-based intervals; design power depends on the implementation Stable treatment-control relationship, match quality, model form, assignment constraints
Meridian GeoX Randomised or stratified assignment with TBR inference at the documented launch boundary Product-specific Randomisation, balance, TBR stability, and delivery integrity
Meta GeoLift Augmented synthetic control with generalised synthetic-control components Conformal and package-specific procedures L2 imbalance, augmentation model, market selection, test fit
Bayesian causal-impact tools Structural time-series counterfactual Posterior distribution Prior/model fit and posterior predictive behaviour

GeoSC’s native power module is simulation-based, but that does not imply a TBR or GeoX MDE is necessarily analytic; implementations vary. GeoSC repeatedly simulates a factor-VAR post period, injects effects, and calls SparseSC. A TBR workflow may use a fitted treatment-control regression, residual variance, analytic formula, resampling, or simulation.

Before comparing MDEs align outcome and transformation, treatment geography, control eligibility, pre-period, measurement and cooldown windows, lift denominator, effect pattern, alpha, target power, one- or two-sided rule, failure handling, and whether placebo assignments are sampled. Before comparing effects align the estimand, scale, aggregation, and uncertainty interpretation.

A material discrepancy is a diagnostic. Decompose it rather than averaging the answers or assuming the larger MDE is conservative. GeoSC is useful when individual donor diagnostics, Python operation, and auditable artefacts matter; it is not automatically superior to a well-specified regression design.

Primary method references

These references describe their respective implementations. They do not imply that an internal or modified workflow uses the same defaults.

Multi-Treatment Designs

GeoSC supports several treated geographies, but interpretation and computation change.

The top-level effect is joint across the treated set; it is not a separate ATT for each geography. Placebo assignments must contain the same number of control units as the treated set, giving \(\binom{N_0}{N_1}\) possible assignments. SparseSC work can grow rapidly, so sparse_sc_max_n_pl may trigger sampling.

Power injects the same absolute effect path into every treated unit, based on the pooled treated pre-period mean. This is not unit-specific proportional lift. When treated units have very different outcome levels, supplement the standard run with a carefully labelled sensitivity analysis or avoid describing the injected effect_size as each unit’s own percentage lift.

Confirm that all treated units share a defensible launch and measurement window. Staggered adoption requires a distinct design argument; do not coerce it into a single-date configuration without defining the resulting estimand.

Placebo Inference

GeoSC uses SparseSC in-space placebo inference because geo experiments often have too few treated units for conventional large-sample approximations.

For each treated-sized subset of eligible controls, SparseSC constructs an honest placebo effect. The top-level p-value compares the absolute average treated effect with the absolute average placebo effects and applies an add-one correction. It is two-sided.

When feasible assignments exceed sparse_sc_max_n_pl, SparseSC samples assignments using sparse_sc_placebo_seed; otherwise it enumerates them. The result reports the possible and effective counts and labels the mode exact, sampled, or unknown.

Finite support matters. With \(M^*\) effective placebos the nominal resolution is \(1/(M^*+1)\). If this exceeds alpha, significance at that alpha cannot be attained. Sampling adds reference-set variability even when the optimiser is stable; preserve the seed.

The p-value is calibrated only relative to the placebo assignment logic and its exchangeability assumptions. Non-comparable donors, spillover, differential measurement changes, or poor pre-fit can make a numerically small p-value misleading. SparseSC placebo intervals are likewise finite-reference-set quantities, not model-free guarantees.

Power and MDE Methodology

GeoSC power is a simulation-based design diagnostic. For effect \(e\) and duration \(d\), it estimates

$$ \widehat{Power}(e,d) = \frac{\text{successful simulations with }p < \alpha} {\text{successful simulations}}. $$

Failed simulations are excluded from the denominator and reported separately. A row is valid only when at least one simulation succeeds and its failure rate does not exceed power_failure_rate_threshold. Validity does not assert that the DGP or design assumptions are credible.

Implemented workflow

For every effect-duration grid point, GeoSC:

  1. pivots the long CSV to a unit-by-period matrix;
  2. uses periods before treatment_date as the fixed observed pre-period;
  3. demeans each unit, fits an SVD factor model, and estimates factor dynamics;
  4. simulates a post-period panel;
  5. computes one baseline as the mean across all treated units and all pre-periods;
  6. multiplies that pooled baseline by effect_size and applies the resulting same absolute effect path to every treated unit;
  7. appends simulated post data to the observed pre-period;
  8. calls SparseSC with treated periods at the split and counts results.p_value < alpha.

This denominator means a configured 10% lift is relative to the pooled treated pre-period mean. It is not a separate 10% of each treated unit’s own baseline. The output records the baseline and full absolute injection.

The power loop uses the SparseSC estimator and its top-level placebo p-value, but it is not identical to geosc infer. It does not run inference’s panel policies, cooldown resolver, assumption checks, CI configuration, result processor, or full SparseSC config surface. “Same inference path” is therefore too strong; align panels and settings explicitly.

Effect patterns

  • constant and immediate: full absolute effect in every simulated period;
  • ramp: linear sequence from zero to full effect, inclusive;
  • decay: full effect followed by \(\exp(-0.1t)\) decay;
  • any other value: configuration error.

The 0.1 decay rate is not configurable in version 0.3.0.

Grid-based MDE

For duration \(d\) and target power \(q\), GeoSC reports the smallest valid tested effect that reaches the target:

$$ MDE_d = \min\{e \in \mathcal E: valid(e,d),\ \widehat{Power}(e,d) \geq q\}. $$

target_power defaults to 0.80 in the CLI and pipeline but is configurable. No interpolation is performed. If no effect reaches the target, MDE is above the tested range.

Monte Carlo uncertainty

The CSV includes a Wilson interval around the estimated detection proportion. Its confidence setting uses the configured alpha. This interval describes finite simulation uncertainty, not DGP misspecification, donor-selection uncertainty, or future-campaign uncertainty. If it straddles target power, increase n_simulations before making a threshold decision.

Worked output

duration effect_size power interval failure_rate valid
28 0.05 0.42 0.36–0.48 0.00 true
28 0.10 0.76 0.71–0.81 0.00 true
28 0.15 0.91 0.87–0.94 0.00 true
35 0.10 0.84 0.79–0.88 0.00 true
42 0.10 0.89 0.85–0.92 0.25 false

At 80% target power, the 28-period grid-based MDE is 15% and the 35-period MDE is 10%. The 42-period row is excluded despite high estimated power.

Power is computationally intensive because total work scales approximately with effect sizes × durations × simulations × SparseSC fit and placebo cost. This differs from a closed-form regression MDE, but computational intensity is not by itself evidence of better calibration.

Power DGP Assumptions

GeoSC estimates its power data-generating process (DGP) from the pre-period outcome matrix.

Each unit is demeaned. Singular value decomposition produces factor loadings and factor scores. When rank is automatic, GeoSC chooses the first rank reaching about 80% cumulative singular-value variance, bounded by power_dgp_max_rank and a short-panel VAR feasibility cap. It then estimates a VAR(1) intercept, transition matrix, and Gaussian innovation covariance on the factor series.

Simulation draws the initial factor state from the estimated marginal normal distribution; it is not conditioned on the final observed factor state. Later states follow the fitted VAR(1). Outcomes combine fixed unit loadings, simulated factors, stored unit means, and independent Gaussian idiosyncratic noise with one pooled residual standard deviation.

Consequences:

  • cross-unit dependence is represented through common factors;
  • lag-one factor dependence is represented;
  • calendar seasonality is not modelled explicitly;
  • the fitted VAR transition is not constrained to be dynamically stable;
  • idiosyncratic variance is homoskedastic across units and periods;
  • non-Gaussian tails, structural breaks, intermittent zeros, and conditional start-state dynamics may be poorly represented;
  • rank selection is a heuristic, not cross-validated DGP truth.

Validate simulated moments and time-series behaviour against the use case. Run sensitivity to history, rank, effect pattern, and eligible controls. If design decisions change materially, report DGP dependence rather than one definitive MDE.

SparseSC Estimator

GeoSC’s only implemented estimator selector is sparsesc. SparseSC learns a regularised match space and donor weights from pre-treatment outcomes and optional covariates.

Conceptually, it chooses unit weights \(W\) and match-space weights \(V\) to reduce treated-versus-synthetic pre-period discrepancy subject to regularisation:

$$ (\widehat W, \widehat V) = \arg\min_{W,V} \left|Y^{pre}{\mathcal T}-Y^{pre}{\mathcal C}W\right|_V^2

  • \mathcal P_W(W) + \mathcal P_V(V). $$

This is an explanatory simplification, not a line-by-line restatement of every vendored optimisation path. With sparse_sc_fast_estimation: true, GeoSC calls the vendored fast path, which uses RidgeCV-backed match-space machinery. The full path uses SparseSC’s penalty search and coordinate-descent machinery.

Regularisation controls overfit; it does not make an ineligible donor valid. Inspect pre-fit, fitted unit weights, weight concentration, and sensitivity to substantive donor exclusions. The selected_weight from GeoSC’s donor stage is not \(\widehat W\); fitted weights are exposed in inference diagnostics.

The package vendors a pinned, locally governed SparseSC fork. See Vendored Dependencies for provenance.

Spillover, Contamination, and Concurrent Media

Synthetic control requires the donors to represent untreated outcomes. This can fail when audience delivery crosses boundaries, national media reaches both groups, travellers move between geographies, retail or supply changes differ by region, or another campaign starts near treatment.

Concurrent activity is not automatically fatal. A national or business-as-usual channel can be part of the baseline if its effect and delivery are sufficiently common across treated and donor geographies. Differential delivery correlated with treatment is the problem. Record channel, dates, spend or delivery where available, targeting logic, and expected geographic reach.

GeoSC’s interference screen compares outcome behaviour and can return signal, no_signal, or indeterminate. It has no exposure model and cannot establish whether media caused the pattern. Use campaign logs, geographic delivery data, and domain evidence. Keep the screen advisory.

If contamination is material and cannot be represented or excluded, reject the design or change the estimand. Do not reinterpret contaminated donors as valid because pre-period fit was good.

Synthetic-Control Formalism

Let \(Y_{it}\) be the outcome for unit \(i\) and period \(t\). Let \(\mathcal{T}\) denote treated units, \(\mathcal{C}\) eligible donors, and \(T_0\) the last pre-treatment period after any window resolution.

For one treated unit, a synthetic counterfactual has the form

$$ \widehat{Y}_{1t}(0) = \sum_{j \in \mathcal{C}} w_j Y_{jt}. $$

Weights and the match space are estimated from pre-treatment information. The period effect is

$$ \widehat{\tau}_t = Y_{1t} - \widehat{Y}_{1t}(0), $$

and GeoSC’s top-level unscaled ATT is the average of that effect over measured post periods:

$$ \widehat{\tau} = \frac{1}{T_1}\sum_{t=T_0+1}^{T_0+T_1}\widehat{\tau}_t. $$

The implementation also supports multiple treated units. SparseSC constructs a joint treated effect and an in-space placebo reference set formed from treated- sized subsets of controls. With \(N_0\) controls and \(N_1\) treated units, the exhaustive assignment count is

$$ M = \binom{N_0}{N_1}. $$

GeoSC’s top-level p-value is not a post/pre mean-squared prediction-error ratio. If \(\widehat{\tau}^{(m)}\) is the average placebo effect for assignment \(m\), SparseSC uses the two-sided absolute-effect comparison with add-one correction:

$$ p = \frac{1 + \sum_{m=1}^{M^*} \mathbf{1}\left\{|\widehat{\tau}^{(m)}| \geq |\widehat{\tau}|\right\}} {M^*+1}, $$

where \(M^*\) is the effective exhaustive or sampled placebo count. The finest attainable step under this calculation is \(1/(M^*+1)\). The result is an empirical comparison against the eligible placebo assignments; its causal meaning depends on the design.

Getting Started

Subsections of Getting Started

Concepts and Workflow

GeoSC separates design questions that are often blurred together.

Stage Question Main artefact Important limit
Power Could the proposed design detect effects on the tested grid under the fitted simulation DGP? power_analysis_results.csv It does not forecast campaign lift or establish identification.
Donors Which eligible geographies have useful pairwise pre-period similarity to each treated geography? donor_eval_results.csv Recommendations and selected_weight are screening outputs, not fitted SparseSC weights.
Inference How did treated outcomes differ from the SparseSC counterfactual during the measurement period? geolift_results.json Causal interpretation remains conditional on design assumptions.

In GeoSC, a control is a geography not assigned treatment in the input to a stage. A donor is a control geography eligible to contribute to a synthetic counterfactual. Operationally, analysts often use the words interchangeably, but eligibility should be determined before model fitting.

The pipeline executes power, donors, then infer. It does not use donor recommendations to filter the later power or inference inputs. Power uses every non-treatment unit in its input panel as a control. Inference uses the control units present in its prepared panel. If a screening decision should constrain a later stage, create a filtered canonical panel or config and record that hand-off.

Before running any stage, define:

  1. the outcome and its unit of measurement;
  2. the treated geography or geographies;
  3. the treatment launch, cooldown, and measurement window;
  4. donor eligibility and exclusions;
  5. the effect scale, alpha, target power, and reporting rule;
  6. plausible spillover, concurrent-media, and measurement-change mechanisms.

Reject or redesign the study if these decisions cannot be defended. GeoSC is a measurement engine, not a machine for laundering an infeasible design into a number.

First Successful Run

This run checks the installed CLI and artefact path using the source checkout’s synthetic data. It is a software smoke test, not evidence that the demo is a credible client design.

geosc infer \
  --config data-config/geolift_analysis_config.yaml \
  --no-create-plots

A successful command returns exit code 0 and writes these files under the configured inference output directory:

  • geolift_results.json;
  • geolift_diagnostics.json;
  • data_validation.json;
  • assumption_validation.json.

Inspect them in this order:

  1. data_validation.json: confirm the panel, periods, units, and data policies.
  2. geolift_results.json: require status: "ok" or investigate every warning on a partial result. Never report a failed result.
  3. geolift_diagnostics.json: review pre-period fit, placebo support, and donor weight concentration.
  4. assumption_validation.json: distinguish the gate-eligible parallel-trends diagnostic from the advisory interference screen.

Next, replace the demo config with a copy tied to your panel. Follow Prepare an Input Panel before using client data.

Installation

GeoSC 0.3.0 supports Python 3.10 to 3.13. Use an isolated virtual environment.

Install a maintained build

python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install /path/to/geosc-0.3.0-py3-none-any.whl
geosc --help

The build installs both geosc and the compatibility command geolift. It does not include the repository’s data-config/, recipes/, or shapemap/ directories. Supply your own input CSV and YAML files.

Install from a source checkout

git clone https://github.com/tandpds/GeoSC.git
cd GeoSC
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m pip install -e .
geosc --help

Source installation makes the shipped synthetic panel and stage configs available under data-config/.

Optional GPU dependency

CuPy is optional and is used only by parts of unseeded power-analysis DGP estimation or generation when the supported GPU path is available. Main SparseSC inference is CPU-based. A configured random_seed disables GPU DGP and generation paths to preserve reproducible draws. Install a CuPy build that matches the local CUDA runtime; for example:

python -m pip install cupy-cuda12x

GeoSC falls back to CPU when the requested GPU path is unavailable. Record the reported dgp_backend and generation_backend; do not infer GPU use from the configuration alone.

How-to Guides

Subsections of How-to Guides

Define the Estimand and Windows

Write the estimand before configuring GeoSC:

Average difference, in outcome units per observed period, between treated outcomes and their SparseSC counterfactual over the declared measurement window for the declared treated geographies.

GeoSC labels this att_unscaled. The top-level att is the average across the post-period effect path. If several geographies are treated, the SparseSC procedure forms a joint treated effect; do not describe the result as a unit-specific effect unless a separate analysis supports that claim.

Set:

  • intervention_date_str: first observed treatment period;
  • cooldown_periods: observed periods after launch excluded from measurement;
  • optional measurement_start_date_str: explicit start that must agree with the cooldown calculation;
  • min_pre_treatment_periods and min_post_treatment_periods: admissibility thresholds where supplied.

Cooldown periods are neither pre-period fit data nor measured post-period data. They count observations, not calendar units. A seven-period cooldown is seven days only for a complete daily panel.

Pre-specify the end of measurement by trimming the input panel to the intended window. The shipped inference config has no active end_date key.

Define Treatment and Donor Eligibility

Create an eligibility table before running GeoSC. For every geography record:

  • treatment assignment;
  • inclusion or exclusion;
  • reason;
  • decision date and owner;
  • known campaign, operational, or measurement contamination;
  • geographic adjacency or audience leakage concerns.

Eligible donors should be unaffected by treatment, measured consistently, and plausible counterfactual contributors. Pre-period correlation alone is not an eligibility rule. Exclude geographies for design reasons established without post-treatment outcomes.

Power treats every non-treatment unit in its input as a control. Donor evaluation scores every eligible non-treatment unit in its own input. Inference uses the controls in its prepared panel. GeoSC does not automatically apply the donor recommendations to the other stages. Materialise the approved universe as a versioned panel and reuse it across the stages.

For several treated geographies, confirm that the donor pool can support joint in-space placebo assignments: with \(N_0\) controls and \(N_1\) treated units, the exhaustive assignment count is \(\binom{N_0}{N_1}\), provided \(N_0 \geq N_1\).

Diagnose a Weak Design

Work from failure mechanism to remedy.

Symptom Likely issue Action
Poor pre-period fit Donors cannot reproduce treated dynamics Revisit eligibility, geography level, outcome, and comparable history.
Coarse p-value granularity Too few effective placebo assignments Add eligible controls or reduce treated count only if the design permits it.
Dominant fitted donor weight Counterfactual depends on one geography Audit that donor and run exclusion sensitivity.
High power failure rate SparseSC or DGP instability Inspect exceptions, rank, panel completeness, and placebo feasibility.
High grid-based MDE Noise or weak counterfactual relative to plausible lift Redesign duration, outcome, treated scale, or method before launch.
Interference signal Outcome changes among controls are compatible with contamination Investigate exposure using campaign and geographic evidence; the screen is not causal proof.
Result partial Missing uncertainty or warnings Resolve the stated fields before decision use.

Do not tune exclusions, dates, or donors by searching for significance. If the remedy changes the design, rerun power and record the new specification.

Evaluate Donors

Run donor evaluation on pre-treatment data after applying substantive eligibility exclusions.

geosc donors --config data-config/donor_eval_config.yaml --jobs -1

The evaluator aligns each treatment-donor pair by time, then calculates Pearson correlation and its p-value, root mean squared error (RMSE), percentage RMSE, mean absolute percentage error (MAPE), and normalised dynamic time-warping (DTW) distance. It normalises metrics within each treated geography, combines them using configured or adaptive weights, and ranks complete rows.

Review:

  • overlap_count, treatment_coverage, and donor_coverage before scores;
  • metrics_complete and metric_failure_reasons;
  • correlation, rmse, mape, and dtw, not only composite_score;
  • warning_flags, quality bands, concentration, and effective donor count;
  • maps only as a geographic diagnostic, not as proof of comparability.

selected_weight is normalised from positive composite scores among the recommended donors. Its role is design_stage_recommendation_weight; it is not a fitted SparseSC counterfactual weight.

The evaluator’s output is a screening artefact. If it changes the donor pool, filter the canonical panel and rerun power and inference. To render maps, see Use Shapemaps.

How to Use Shapemaps

GeoSC donor-stage maps use shapemap_file to read a GeoPandas-compatible vector file and shapemap_id_column to choose the geography ID used for joins. The values in that ID column must match the unit IDs used in your experiment data, such as DMA IDs, postcode districts, postcode areas, or another market key. The inference and power stages do not consume shapemap configuration.

Built wheel and sdist installs do not include the repository-local shapemap/ directory. Packaged users should provide map files from their own runtime environment.

Basic Config

shapemap_file: "/path/to/markets.geojson"
shapemap_id_column: "id"

GeoSC can read formats supported by GeoPandas, including GeoJSON, TopoJSON, Shapefile, and GeoPackage inputs when the local geospatial stack supports them.

Repository-local shapemap examples are available for common markets:

  • shapemap/uk/postcode_areas.geojson
  • shapemap/uk/postcode_districts.geojson
  • shapemap/us/dma_legacy_normalized.geojson
  • shapemap/fr/fr_nuts3.geojson
  • shapemap/de/de_nuts3.geojson
  • shapemap/uk/meta_commuting_zones.geojson
  • shapemap/us/meta_commuting_zones.geojson
  • shapemap/fr/fr_meta_commuting_zones.geojson
  • shapemap/de/de_meta_commuting_zones.geojson

These are source-checkout assets. They are not included in built wheel or sdist artifacts.

Meta Commuting Zones are also available as optional geographies for Meta-aligned study design. They are commuting/economic zones, not Meta ad-targeting boundaries.

UK Postcode District Example

For UK production workflows, postcode district is often the practical market geography:

location_col_name: "postcode_district"
treatment_locations: ["SW1A", "M1"]
shapemap_file: "/secure/maps/uk_postcode_districts.geojson"
shapemap_id_column: "id"

The input data must use the same IDs as the shapemap:

postcode_district,date,Y
SW1A,01/01/2025,125.3
SW1A,02/01/2025,128.7
M1,01/01/2025,98.2

Use scripts/prepare_uk_postcode_shapemap.py from a source checkout to normalize licensed or user-supplied postcode polygon data:

python scripts/prepare_uk_postcode_shapemap.py \
  --input /path/to/licensed-postcode-polygons.gpkg \
  --output shapemap/uk/postcode_districts.geojson \
  --level district \
  --postcode-column postcode \
  --metadata-output shapemap/uk/postcode_districts.metadata.json

The generated file exposes:

  • id: postcode district, such as SW1A, M1, or BT7
  • name: display name, defaulting to the same value as id
  • country: UK
  • geography_level: postcode_district
  • geometry: dissolved polygon geometry

The repository includes an approximate version built from ONSPD live postcode centroids. Its metadata file retains the derivation year in its name:

location_col_name: "postcode_district"
treatment_locations: ["SW1A", "M1"]
shapemap_file: "shapemap/uk/postcode_districts.geojson"
shapemap_id_column: "id"

Validate the generated file before using it in donor evaluation:

python scripts/validate_shapemap.py \
  --shapemap shapemap/uk/postcode_districts.geojson \
  --id-column id \
  --expected-ids SW1A,M1 \
  --json

UK Postcode Area Example

For broader UK markets, use postcode areas:

location_col_name: "postcode_area"
treatment_locations: ["SW", "M"]
shapemap_file: "/secure/maps/uk_postcode_areas.geojson"
shapemap_id_column: "id"

Prepare the map with:

python scripts/prepare_uk_postcode_shapemap.py \
  --input /path/to/licensed-postcode-polygons.gpkg \
  --output shapemap/uk/postcode_areas.geojson \
  --level area \
  --postcode-column postcode

Provenance and Licensing

Do not commit or distribute postcode geometry unless the source license permits that use. The repository records shapemap provenance policy in shapemap/README.md and shapemap/manifest.yaml.

For UK data:

  • OS Code-Point Open is an open postcode unit point dataset, not polygon geometry.
  • OS Code-Point with Polygons is the appropriate official polygon source when you have the necessary access and licensing.
  • ONS Postcode Directory is useful for postcode-to-geography lookup workflows.

Troubleshooting

If donor maps do not highlight treatment or donor units:

  • confirm the shapemap contains the configured shapemap_id_column
  • confirm the shapemap ID values exactly match the experiment unit IDs
  • normalize both sides to the same case and spacing convention
  • confirm the file can be opened by geopandas.read_file

scripts/validate_shapemap.py reports missing expected IDs, duplicate IDs, blank IDs, null or empty geometry, invalid geometry, row counts, unique ID counts, and the detected CRS.

Prepare an Input Panel

Use a long CSV with one row per geography and observed period. The inference loader requires configured date, geography, and outcome columns; treatment is defined in YAML, not read from a treatment flag in the CSV.

Required checks

  1. Use stable geography identifiers and one geographic level.
  2. Use a regular time interval appropriate to the campaign and outcome.
  3. Confirm that every intended unit-period has one finite outcome.
  4. Make the intervention date an observed period.
  5. Preserve enough observations before and after the resolved measurement start.
  6. Use a consistent outcome definition, currency, attribution window, and data production process across geographies and time.

Inference defaults to duplicate_policy: error and missing_outcome_policy: error. Alternative policies are explicit analytical decisions. mean or sum changes duplicate rows before pivoting; drop_unit, drop_period, or impute_with_report changes the estimable panel.

data_path: data/client_panel.csv
date_col_name: date
location_col_name: region_id
outcome_col_name: revenue
date_format: "%Y-%m-%d"
treatment_unit_ids: ["FRJ"]
intervention_date_str: "2026-09-01"
duplicate_policy: error
missing_outcome_policy: error

Do not use locale-dependent date parsing in an audited run. After execution, review data_validation.json; a successful model does not supersede a failed data contract.

Produce a Stakeholder Summary

Lead with the decision and its conditions. A compact summary should include:

  • treated geography, outcome, launch, cooldown, and measurement dates;
  • eligible donor universe and material exclusions;
  • design-stage MDE at the stated target power and plausible lift range;
  • inference status, ATT in outcome units, interval, p-value, and placebo count;
  • pre-period fit and donor concentration;
  • concurrent media, spillover, data, and sensitivity caveats;
  • a clear recommendation: proceed, interpret cautiously, redesign, or reject.

Example:

GeoSC estimated average incremental revenue of £X per week against the pre-specified SparseSC counterfactual over dates A–B. The two-sided in-space placebo p-value was P using N placebo assignments; the interval was [L, U]. Interpretation is conditional on the recorded donor-eligibility and treatment- isolation assumptions. The design-stage grid-based MDE was M% at T% target power, so effects below M% were not reliably detectable under the fitted DGP.

Do not translate statistical significance into ROI without campaign cost and a commercial value definition. Do not describe status: ok as proof of causal validity.

Run Inference

Freeze the panel and inference YAML before viewing post-treatment results, then run:

geosc infer \
  --config data-config/geolift_analysis_config.yaml \
  --create-plots

Use --data to override only the CSV path and --no-create-plots to suppress plotting. The command returns non-zero when the stage raises an error or the result status is failed.

Review outputs in this order:

  1. data_validation.json for panel construction and window metadata;
  2. assumption_validation.json for the parallel-trends gate and advisory interference screen;
  3. geolift_results.json for status, unscaled ATT, p-value, interval, placebo count, granularity, warnings, and errors;
  4. geolift_diagnostics.json for pre-fit and fitted donor-weight diagnostics;
  5. uplift_timeseries.png as a visual diagnostic.

Describe the result as an estimated difference from the configured SparseSC counterfactual. Causal interpretation requires defensible donor exchangeability, treatment isolation, stable measurement, timing, and absence of material unmodelled shocks. The advisory interference screen cannot prove or disprove spillover.

Run Power Analysis

Define a plausible effect grid and duration grid, then run:

geosc power --config data-config/power_analysis_config.yaml --jobs -1

Use a fixed random_seed for an audited run. Seeded runs use CPU simulation paths. Start with a small n_simulations only to debug the configuration, then increase it until Monte Carlo intervals are adequate for the decision.

For each row:

  1. require valid: true;
  2. inspect failure_rate and warnings;
  3. compare power with its Wilson interval;
  4. verify the DGP rank, explained variance, backends, placebo support, and injection metadata;
  5. interpret MDE as the smallest tested effect reaching target_power for a duration.

GeoSC does not interpolate between effect sizes. If no grid value reaches the target, report MDE as greater than the maximum tested effect. The CLI’s default planning threshold is 80%; it is configurable through target_power and is not a statistical property of SparseSC.

Power uses the SparseSC estimator and p-value detection rule inside each simulation, but it does not execute the full inference workflow. It does not run inference data policies, cooldown resolution, assumption checks, result processing, or plotting. Align the power input panel and intervention split with the intended inference design yourself.

Run Sensitivity Analysis

Pre-specify a small set of defensible perturbations:

  • alternative comparable pre-period windows;
  • exclusion of a substantively suspect or dominant donor;
  • plausible cooldown or measurement-start choices;
  • DGP rank and effect-pattern choices for power;
  • outcome definitions fixed before post-period inspection;
  • eligible geography aggregations justified by media delivery and spillover.

For each run, save its panel hash, config, artefacts, and rationale. Compare ATT, intervals, p-values, pre-fit, donor weights, placebo support, MDE, and failure rates. Distinguish robustness to a design choice from fishing over arbitrary specifications.

If the decision changes under small, equally defensible perturbations, report the result as specification-sensitive. Do not average incompatible estimands.

Run the Pipeline

Place the three canonical stage configs in one directory, then point the pipeline at any one of them:

geosc pipeline \
  --config config/geolift_analysis_config.yaml \
  --output-dir outputs/run_001

The required filenames are power_analysis_config.yaml, donor_eval_config.yaml, and geolift_analysis_config.yaml. The command runs power, donors, then inference and writes Markdown and HTML summaries by default.

Useful selectors:

geosc pipeline --config config/geolift_analysis_config.yaml --skip-power
geosc pipeline --config config/geolift_analysis_config.yaml --skip-donor
geosc pipeline --config config/geolift_analysis_config.yaml --only-inference
geosc pipeline --config config/geolift_analysis_config.yaml --no-report

--output-dir creates the legacy stage subdirectories below the supplied root. --jobs and --use-gpu are passed as runtime overrides, subject to each stage’s support.

The pipeline is an orchestrator, not a design-state engine. Donor recommendations do not filter power or inference inputs. The compact report is not a decision gate; inspect each underlying artefact and record any manual panel hand-off.

Use the Python API

For file-based inference, initialise the public analyser with a config and data path:

from geolift import GeoLiftAnalyzer

analyser = GeoLiftAnalyzer(
    config_path="config/inference.yaml",
    data_path="data/panel.csv",
)
result = analyser.run_analysis()

if result["status"] == "failed":
    raise RuntimeError(result["errors"])
if result["status"] == "partial":
    print("Review warnings:", result["warnings"])

Direct-data construction is also supported by GeoLiftAnalyzer; the panel must be wide with units as rows and datetime-like periods as columns, with a unit- indexed treatment-period series. Use the Python API reference for signatures.

Power is available through geolift.power.SparseSCPowerCalculator. Donor screening is available through geolift.donor_evaluator.DonorEvaluator, but neither is re-exported from the package root. Prefer the CLI for versioned file-based runs because it writes the maintained artefact family.

Validate a Power Simulation

Treat a power run as a model requiring diagnostics.

Reproducibility

Repeat the same CPU run with the same seed and compare the CSVs. Record the package version, input hash, YAML, seed, and execution backends.

Monte Carlo precision

Use power_ci_lower and power_ci_upper. If the interval straddles the target power, increase simulations before making a boundary decision. The interval quantifies simulation-count uncertainty only; it does not include uncertainty about the DGP specification.

DGP plausibility

Review dgp_rank, dgp_explained_var, and dgp_factor_dynamics. Compare observed and simulated distributions outside GeoSC where the decision is material: unit means and variances, cross-unit correlations, autocorrelation, seasonal patterns, extremes, and zeros. The current DGP does not model calendar effects or heteroskedastic idiosyncratic noise explicitly.

Grid stability

Power should usually rise with larger injected effects in a well-resolved simulation, but finite Monte Carlo estimates can move up or down. Investigate large reversals, high failure rates, coarse placebo p-values, or sensitivity to rank, history window, seed, donor eligibility, and effect pattern.

Do not call the run validated merely because all rows are valid. That flag only checks that at least one simulation succeeded and that the failure rate did not exceed the configured threshold.

Reference

Subsections of Reference

CLI Reference

GeoSC installs geosc and the compatibility alias geolift. Both dispatch to the same parser.

geosc {power,donors,infer,pipeline} --config PATH [shared options]

Shared options

Option Meaning
--config PATH Required YAML path. For pipeline, it is an anchor in a directory containing all three canonical configs.
--output-dir PATH Overrides a stage output directory, or the pipeline output root.
--jobs N Overrides n_jobs; for power and donors it also enables parallel execution.
--use-gpu Requests supported GPU work. It does not enable GPU inference.
--no-progress Disables progress displays.
--quiet Reduces non-critical terminal output; artefacts are still written.

Inference-only options

Option Meaning
--data PATH Overrides data_path.
--create-plots Forces plot generation.
--no-create-plots Disables plot generation.

Pipeline-only options

Option Meaning
--skip-power Omits the power stage.
--skip-donor Omits donor evaluation.
--only-inference Omits both design stages.
--report / --no-report Enables or disables compact Markdown and HTML reports. Reports are enabled by default.

Exit codes

0 means the requested stage completed under its software contract. 1 means a stage failed during validation or execution, including inference returning status: failed. 2 means argument parsing or initial CLI configuration resolution failed. An ok exit does not establish causal validity. See Errors and Exit Codes.

Configuration

Subsections of Configuration

Donor Configuration

Key Type/default Contract
schema_version string, 1.0 Config version.
data_path string Long CSV containing date, location, and Y or metric.
date_format string or omitted Explicit source date format.
treatment_locations list Treated identifiers, compared after string conversion.
treatment_date string Pre/post split; only pre-period rows are scored.
max_donors integer, 10 Maximum complete recommendations per treated unit.
min_correlation_threshold float, 0.7 Adds low-correlation warnings.
max_rmse_threshold float or null Adds high-RMSE warnings.
donor_dominance_threshold float, 0.5 Adds dominance warnings for recommendation weights.
min_excellent_donors integer, 3 Pool-summary threshold.
min_good_donors integer, 5 Pool-summary threshold.
mape_thresholds mapping acceptable (default 30) controls high-MAPE warnings; other labels are retained compatibility settings.
shapemap_file string or null GeoPandas-readable vector file.
shapemap_id_column string Geography key in the vector file.
output_dir string Artefact directory.
parallel boolean Parallel pair scoring.
n_jobs integer Worker count; -1 uses all cores.

The current donor stage always computes correlation, RMSE, MAPE, and DTW. There are no active evaluation_metrics, pre_treatment_periods, min_donors, limit_donor_pool, top_correlated_donors, acceptable_mape, or correlation_thresholds keys.

Inference Configuration

The shipped inference YAML is the canonical example. Active keys are listed below; unknown non-sparse_sc_* keys are not comprehensively rejected, so a misspelling can be ignored. Compare production configs with this table.

Key Type/default Contract
schema_version string, 1.0 Supported config schema.
data_path string Input CSV for file mode.
location_col_name string Geography identifier column.
date_col_name string Period column.
date_format string Explicit pandas date format.
outcome_col_name string Numeric outcome column.
covariate_col_names list or null Optional covariates passed to the loader.
treatment_unit_ids list Treated geography identifiers.
intervention_date_str string First observed treated period.
cooldown_periods non-negative integer, 0 Observed periods excluded after launch.
measurement_start_date_str string or null Optional explicit start; must agree with cooldown.
duplicate_policy error, mean, sum Duplicate unit-period handling.
missing_outcome_policy error, drop_unit, drop_period, impute_with_report Incomplete-panel handling.
min_pre_treatment_periods integer Minimum pre-period observations when supplied.
min_post_treatment_periods integer Minimum measured post-period observations when supplied.
estimator sparsesc Only implemented estimator selector.
output_dir string Artefact directory.
create_plots boolean CLI plot default.

SparseSC runtime keys:

Key Default or role
sparse_sc_model_type SparseSC model type, normally retrospective.
sparse_sc_fast_estimation Selects SparseSC fast fitting path.
sparse_sc_return_ci Requests placebo confidence intervals.
sparse_sc_T0, sparse_sc_T1 SparseSC history-length controls; not cooldown semantics.
sparse_sc_max_n_pl Maximum placebo assignments used.
sparse_sc_placebo_seed Non-negative seed for sampled placebo assignments; default 110011.
sparse_sc_level Requested interval level.
sparse_sc_lasso_max_iter, sparse_sc_lasso_tol Forwarded as fast-path CV options; the RidgeCV-backed path may ignore them. They do not configure the full path.
sparse_sc_cv_folds, sparse_sc_scoring, sparse_sc_gcv_mode Supported adapter controls.

Assumption keys are run_assumption_checks, require_assumption_checks, fail_on_assumption_error, parallel_trends_method, spillover_method, and assumption_alpha. Only the parallel-trends diagnostic is gate-eligible. The interference screen is always advisory.

The non-prefixed compatibility keys lasso_selection, lasso_fit_intercept, and lasso_normalize are forwarded only when the fast path is selected. Their support depends on the installed scikit-learn API; prefer the documented sparse_sc_* controls for new configurations.

There is no active treatment_col or end_date key. Define treatment through treatment_unit_ids; trim the input panel to a pre-specified end date. Inference also does not consume shapemap_file or shapemap_id_column; shapemap-backed maps belong to the donor stage.

Power Configuration

Key Type/default Contract
schema_version string, 1.0 Config version.
data_path string Long CSV.
date_col, location_col, outcome_col strings Source columns.
treatment_locations list Treated units; numeric-looking strings are coerced to integers.
treatment_date string Split used to estimate the pre-period DGP.
duration list of integers Simulated post-period lengths. Alias: test_durations.
effect_sizes list of floats Relative injected lifts. Alias: effect_size.
alpha float, 0.05 Detection threshold; must be in (0, 1).
target_power float, 0.80 CLI MDE/report threshold; must be in (0, 1].
n_simulations integer, 1000 Repetitions per grid row.
effect_pattern string, constant constant, immediate, ramp, or decay.
random_seed integer or null Reproducible configuration seed.
power_dgp_rank integer or null Explicit SVD rank.
power_dgp_max_rank integer, 5 in CLI Automatic rank cap.
power_failure_rate_threshold float, 0.20 Maximum valid row failure rate.
sparse_sc_max_n_pl positive integer, 100 Requested placebo cap.
parallel, n_jobs boolean, integer Grid-level CPU parallelism.
use_gpu boolean Optional unseeded DGP acceleration request.
output_dir string CSV and plot directory.

constant and immediate currently produce the same full effect in every period. ramp moves linearly from zero to the full effect. decay applies the full effect initially and a hard-coded exponential decay rate of 0.1 per period. Unknown patterns fail.

The CLI power path forwards a deliberately narrower SparseSC configuration than inference: fast estimation, placebo cap, DGP controls, seed, GPU request, and progress state. Inference options such as cooldown, assumption checks, CI level, and lasso controls are not inherited.

Errors and Exit Codes

Signal Meaning Recovery
Exit 0 Command completed its software contract. Inspect artefact statuses and diagnostics.
Exit 1 A resolved stage failed during validation or execution, or inference returned failed. Read the terminal error and stage logs; no reportable result is available.
Exit 2 Argument parsing or initial CLI configuration resolution failed. Correct the command syntax or config path/content.
GeoLiftConfigError Config file, value, or supported SparseSC key is invalid. Correct the named key or path.
GeoLiftDataError / analysis data error Panel cannot be prepared under the selected policy. Fix identifiers, dates, duplicates, gaps, non-finite values, or windows.
GeoLiftResultsError SparseSC output cannot satisfy the result contract. Preserve logs and inspect estimator output; do not substitute zeros.
GeoLiftPlotterError Plot construction failed. Use JSON results only after verifying they completed; fix map or plotting inputs separately.
Power valid: false No successful simulations or failure rate above threshold. Do not use the row for MDE; diagnose simulation failures.
Inference partial Estimate exists with warnings or incomplete uncertainty. Resolve or disclose every warning before use.
Inference failed Required result fields or gates failed. Do not report an effect; redesign or repair.

Unknown non-sparse_sc_* YAML keys are not comprehensively rejected. If a setting appears ineffective, compare it with the exact stage configuration reference rather than assuming it was applied.

Input Schema

Inference and power

Both stages consume a long CSV and pivot it to a unit-by-period outcome matrix.

Field role Required property
Geography Stable scalar identifier; treatment IDs must match after the stage’s documented coercion.
Period Parseable date or time label; inference canonicalises to a sorted, timezone-naive DatetimeIndex.
Outcome Numeric and finite under the configured data policy.
Covariates Optional inference columns named by covariate_col_names.

Power currently uses DataFrame.pivot, so duplicate unit-period rows fail and missing cells remain in the wide matrix. It does not apply inference’s explicit duplicate or missing-outcome policies. Validate and canonicalise the panel before power analysis.

Donor evaluation

The donor stage expects literal source columns date, location, and either Y or metric. It uses rows before treatment_date. Each treatment-donor pair is aligned on unique parsed dates; duplicates or insufficient finite overlap produce incomplete metrics.

Store the panel frequency, timezone policy, outcome unit, currency, attribution logic, geography version, extract timestamp, source owner, and row-count checks alongside the CSV. These are project data-governance requirements, not fields GeoSC can infer.

Output Schemas

Subsections of Output Schemas

Donor Artefact Schemas

donor_eval_results.csv

Each row is a treated-candidate donor pair. Maintained columns include treatment and donor IDs; composite, fit, correlation, and seasonality scores; design-stage recommendation weight and role; rank; quality labels; warnings; metric failure reasons; correlation and its p-value; RMSE, percentage RMSE, MAPE, DTW; and metrics_complete.

Score normalisation and ranking occur within each treated geography. Cross- treatment score values are therefore not a common absolute scale.

donor_pool_quality.json

Schema 1.0 records run configuration, an overall summary, and by_treatment summaries. Summary fields include recommendation counts, quality distribution, warning and metric-failure counts, weight role, maximum weight, dominant donor count, effective donor count, score and correlation summaries, strength score, and quality_assessment.

quality_assessment is a deterministic screening label derived from configured thresholds. It is not a test of exchangeability and does not guarantee good SparseSC fit.

Inference Result Schemas

geolift_results.json

Schema 1.0 contains the primary unscaled result:

Field Contract
status ok, partial, or failed.
estimand att_unscaled.
att Average post-period treated-minus-counterfactual effect in outcome units.
p_value Two-sided in-space placebo p-value for the average effect.
p_value_method in_space_placebo.
n_placebos, max_n_placebos, possible_placebos, p_value_placebo_mode, placebo_seed, p_value_granularity Finite reference-set metadata.
ci_lower, ci_upper, ci, ci_source Unscaled SparseSC placebo interval or explicit unavailability.
se / se_available No estimator-provided standard error is claimed.
se_approx_from_ci Optional normal approximation from interval width; not a sampling SE.
significance_available, significant Detection availability and p_value < alpha flag.
analysis_window Launch, cooldown, and measurement metadata.
assumption_status, assumption_required, assumption_checks_completed Gate summary.
warnings, errors, caveats Interpretation controls.

geolift_diagnostics.json

Contains pre-period RMS effect and p-value, scaled post-effect diagnostics, period effects, fitted donor-weight summaries, synthetic-control availability, assumption state, analysis window, and warnings/errors. Scaled effects are not interchangeable with the unscaled top-level ATT and interval.

Validation artefacts

data_validation.json records file and model panel construction. assumption_validation.json schema 1.1 records gate-eligible parallel-trends status plus an advisory interference screen with signal, no_signal, or indeterminate status.

Pipeline Report Schema

The pipeline writes geolift_pipeline_report.md and geolift_pipeline_report.html. Each identifies the three config paths and summarises available stage artefacts.

The power section reports grid-based MDE by duration at configured target_power and excludes rows where valid is false. The donor section lists the five highest composite-score rows per treatment from the CSV. The inference section reports available ATT, p-value, interval, and assumption status.

These reports are convenience summaries. They do not contain the full data validation, power failure diagnostics, donor pool quality JSON, assumption checks, or sensitivity evidence. Audit and interpret the source artefacts.

Power Analysis Results Schema

power_analysis_results.csv has one row per effect-size and duration pair.

Field Meaning
schema_version Row contract version (1.0).
target_power CLI planning threshold copied from YAML.
effect_size, duration, alpha Simulated grid and detection threshold.
power n_significant / n_successful.
power_ci_lower, power_ci_upper Wilson interval using alpha as the interval tail setting.
n_simulations, n_successful, n_significant, n_failed Monte Carlo counts.
failure_rate, failure_rate_threshold, valid Failure diagnostics. valid does not validate DGP plausibility.
random_seed, simulation_seed, placebo_seed_root, placebo_seed_strategy Reproducibility metadata.
dgp_rank, dgp_explained_var, dgp_factor_dynamics Fitted DGP metadata.
requested_max_n_pl, possible_placebos, effective_max_n_pl, p_value_placebo_mode Placebo support.
dgp_backend, generation_backend, seeded_reproducibility_mode Execution metadata.
effect_pattern, effect_baseline, effect_full_absolute, effect_baseline_definition Injection contract.
detection_rule, power_denominator Explicit detection and denominator labels.
warnings Semicolon-delimited row warnings.

Direct calls to SparseSCPowerCalculator.calculate_power() do not add the CLI’s target_power column; target power affects MDE selection, not simulation.

Python API Reference

The package root exports the following maintained names:

Name Purpose
__version__ Installed GeoSC version.
GeoLiftAnalyzer File-based or direct-data SparseSC analysis façade.
load_config Load YAML or JSON and optionally validate the common config contract.
load_and_prepare_data Prepare a long input CSV for inference.
process_sparse_sc_results Convert a SparseSC result into result and diagnostic dictionaries.
plot_actual_vs_synthetic Plot observed and synthetic outcome paths.
validate_geolift_dependencies Check required import availability.
GeoLiftConfigError Configuration error.
GeoLiftDataError Data loading or panel error.
GeoLiftResultsError SparseSC result-processing error.
GeoLiftPlotterError Plot construction error.

Import from geolift:

from geolift import GeoLiftAnalyzer, load_config

Specialist classes are available from their modules rather than the package root:

from geolift.donor_evaluator import DonorEvaluator
from geolift.power import SparseSCPowerCalculator

GeoLiftAnalyzer

Use GeoLiftAnalyzer(config_path=..., data_path=..., config=...) for file mode. The optional config mapping overrides top-level keys after file loading. Use the constructor’s direct-data arguments for an already prepared wide outcome panel. run_analysis() returns the main result mapping and writes artefacts for file-based runs. plot_results() writes the maintained inference plot.

Stability boundary

The table above describes the public root exports declared by geolift.__all__. Other modules are usable but may have a narrower compatibility contract. The vendored sparsesc package is not a GeoSC public API.

Reproducibility

For every production run retain:

  • GeoSC version and Git commit when run from source;
  • Python version and dependency environment;
  • exact YAML files and CLI command;
  • input file hash, extract timestamp, and geography version;
  • output artefacts and logs;
  • all random seeds and reported backend fields;
  • eligibility, exclusions, estimand, and window decisions.

Inference defaults sampled-placebo work to sparse_sc_placebo_seed: 110011. Power uses random_seed to spawn per-grid seeds and then per-simulation placebo seeds. Repeated seeded CPU runs with identical inputs and configuration are designed to reproduce their simulation rows. Parallel and sequential seeded runs share the configuration-seed strategy.

When a power seed is set, GPU DGP estimation and generation are disabled. An unseeded GPU run is performance-oriented and should not be treated as bitwise reproducible. Floating-point results can also vary across platforms and library versions; preserve the environment where exact replay matters.

Placebo sampling is reproducible only when the seed and eligible unit ordering are unchanged. Record possible_placebos, effective_max_n_pl, mode, and seed.

Vendored Dependencies

GeoSC vendors Microsoft’s SparseSC under src/sparsesc/ from https://github.com/microsoft/SparseSC at upstream commit 3b4d2ebd87b41fc8e0ec3e97fcb2be1b689275c0. It is a governed integration fork. The authoritative local modifications and update procedure are recorded in src/sparsesc/PROVENANCE.md.

Changes to the vendored tree require a provenance update and wrapper-boundary verification. It is excluded from first-party formatting and typing checks. scripts/verify_release_candidate.py exercises the maintained integration surface; passing that gate does not validate a client design.

src/sparsesc/utils/AzureBatch/ remains part of the governed fork. Removal requires a separate SparseSC provenance-backed phase.

src/synthdid/, if retained in a checkout, is not used by the primary GeoLiftAnalyzer workflow and is not a documented estimator option.

Tutorials

Subsections of Tutorials

End-to-End Synthetic Study

This tutorial uses the repository’s synthetic panel to exercise all three stages and their explicit hand-offs.

1. Inspect the stage configs

The pipeline requires three canonical filenames in one directory:

  • power_analysis_config.yaml;
  • donor_eval_config.yaml;
  • geolift_analysis_config.yaml.

Confirm that all three identify the same outcome, geography universe, treatment units, and launch date. The key names differ by stage; use the stage-specific configuration reference.

2. Run the pipeline

geosc pipeline \
  --config data-config/geolift_analysis_config.yaml \
  --output-dir outputs/tutorial_run \
  --no-progress

The command runs power, donor evaluation, and inference independently. It then summarises their artefacts. It does not feed recommended donors into inference.

3. Review the design outputs

Open multicell_power_analysis/power_analysis_results.csv. Retain only rows where valid is true. MDE is the smallest tested effect_size that reaches target_power for a duration; it is grid-based and conditional on the simulated DGP.

Open multicell_donor_eval/donor_pool_quality.json. Treat quality_assessment: "INSUFFICIENT", incomplete metrics, dominant recommendation weights, or poor overlap as redesign signals.

4. Review inference

Open multicell_geolift_analysis/geolift_results.json. The primary estimate is the unscaled post-period average effect (att). The top-level p_value is the two-sided in-space placebo p-value for that average effect. Scaled quantities remain diagnostics and must not be combined with the unscaled interval.

5. Record the hand-off

If the donor screen changes eligibility, materialise a new panel containing the treated units and approved donors. Rerun power and inference on that same panel. Record the input hash, configs, exclusions, software version, and random seeds.

Failed Donor Design

Consider a treated geography with five recommended donors. Two have incomplete metrics, one receives 70% of the design-stage recommendation weight, and the pool-level quality_assessment is INSUFFICIENT.

This is not a prompt to fit SparseSC and hope regularisation fixes the design. The donor screen says the counterfactual may depend on weak or concentrated comparators. Review time overlap, outcome definitions, treatment leakage, regional shocks, and geography aggregation. Exclude a donor only for a pre-specified eligibility reason, not because its removal improves the eventual effect estimate.

If eligibility changes, rerun donor screening, power, and inference on the same revised geography universe. If no defensible pool remains, reject the design and state which condition failed. See Design Rejection.

Underpowered Design

Suppose a valid power grid contains the following rows for a 28-period test:

effect_size power Monte Carlo interval valid
0.04 0.31 0.27–0.35 true
0.06 0.55 0.50–0.60 true
0.08 0.73 0.68–0.77 true
0.10 0.84 0.80–0.88 true

At an 80% target, the grid-based MDE is 10%. This does not mean that the campaign is expected to deliver 10%, or that effects below 10% are zero. It means the configured procedure detected smaller injected effects less often than the planning threshold under this DGP.

If commercially plausible lift is 4%, the design is underpowered for that decision. Do not solve the problem by reporting an optimistic grid point or by choosing a longer period after seeing outcomes. Consider more comparable donors, lower-noise outcomes, a defensible larger treated population, a longer pre-specified measurement window, or a different design. If none is available, record the design as infeasible before launch.

Also inspect failures. A row with high estimated power and valid: false is not a usable design result. Power is divided by successful simulations, so ignored failures could otherwise make it look better than it is.