Subsections of How-To Guides

How to Evaluate Donor Quality

Selecting the right control (donor) pool is critical for Synthetic Control methods. This guide shows how to evaluate potential donors.

Running Donor Evaluation via CLI

Packaged-install example:

geosc donors --config /path/to/donor_eval_config.yaml --jobs -1

Source-checkout example with the shipped demo config:

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

Built wheel and sdist installs do not include data-config/, so packaged users should provide their own YAML path.

Expected Outputs

  • donor_eval_results.csv: Ranks potential donor regions based on correlation, RMSE, MAPE, and DTW (Dynamic Time Warping) against the treatment unit(s) during the pre-treatment period. Includes quality band, warning flags, per-treatment rank, and normalized recommendation weight.
  • donor_pool_quality.json: Summarizes recommended donor-pool quality and concentration.
  • donor_map_*.png: Visualizations mapping the geographical distribution and quality of the donors (if shapefiles are configured).

selected_weight is a design-stage recommendation weight, not the final SparseSC donor weight used during treatment-effect estimation.

For geography setup, including UK postcode area and postcode district examples, see How to Use Shapemaps.

How to Run a Power Analysis

This guide explains how to use GeoSC to evaluate test strength before running an experiment.

Running Power Analysis via CLI

Use the power command to simulate experiments with known treatment effects and calculate the statistical power:

Packaged-install example:

geosc power --config /path/to/power_analysis_config.yaml --use-gpu --jobs -1

Source-checkout example with the shipped demo config:

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

Key Flags

  • --config: Path to the YAML configuration file.
  • --use-gpu: (Optional) Accelerates computation using compatible GPUs.
  • --jobs -1: Uses all available CPU cores for parallel processing.

Built wheel and sdist installs do not include data-config/, so packaged users should provide their own YAML path.

Expected Outputs

  • power_analysis_results.csv: Detailed grid of simulated lifts, sample sizes, power, Monte Carlo uncertainty, simulation failures, seed, DGP rank, feasible placebo support, and SparseSC/backend parameters.
  • power_curves.png: Visualization of the power curve across different minimal detectable effects (MDE).

Rows with valid: false exceeded the configured simulation failure tolerance or had no successful simulations. Do not use those rows for feasibility decisions. Seeded runs use CPU generation for reproducible simulation draws, so the shipped demo config sets use_gpu: false.

Power DGP

The factor-model power DGP is estimated from pre-treatment outcomes with SVD. GeoSC then estimates VAR(1) dynamics on the extracted factor series and uses those temporal parameters when simulating post-treatment periods. This preserves shared cross-sectional movement through the factor loadings and lag-1 temporal dependence through the VAR(1) transition and innovation covariance.

Covariance matrices are symmetrized and regularized with a small diagonal floor when needed. If VAR(1) dynamics or factor draws cannot be estimated safely, power analysis fails with an actionable error instead of silently switching to a diagonal-covariance DGP. Legacy direct calls to the generator without VAR(1) metadata still use independent factor draws from the supplied F_mean and F_cov.

Current VAR(1) post-period generation runs on CPU so seeded and unseeded power simulations preserve the same temporal contract. GPU acceleration may still be used for eligible DGP estimation, but generated post-period panels from the VAR(1) DGP are produced by NumPy.

Design Validity and Plot Filtering

The power calculator fails fast at construction with a ValueError if the design has no treatment units, or if there are fewer control units than treatment units. In that case placebo inference is infeasible and no power analysis is run.

plot_power_curves filters rows where valid is false out of the decision plots (logging the number of excluded rows), and skips plot creation entirely if no valid rows remain. Inspect power_analysis_results.csv directly to see why rows were marked invalid (high failure_rate, zero n_successful, etc.).

Reproducibility

When random_seed is set, repeated runs of the same config produce identical power_analysis_results.csv content (excluding timestamp/path metadata), in both sequential and parallel modes. This is covered by both unit and CLI integration tests.

How to Run Causal Inference

This guide explains how to measure lift (the actual causal effect) post-experiment using SparseSC.

Running Inference via CLI

Packaged-install example:

geosc infer --config /path/to/geolift_analysis_config.yaml --create-plots

Source-checkout example with the shipped demo config:

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

Key Flags

  • --data: (Optional) Override the CSV path specified in the YAML.
  • --create-plots / --no-create-plots: Toggle generation of visualization artifacts.

Built wheel and sdist installs do not include data-config/, so packaged users should provide their own YAML path.

Expected Outputs

  • geolift_results.json: Top-level statistical results including status, ATT, p-value, and confidence interval metadata.
  • geolift_diagnostics.json: Schema-shaped diagnostic metrics for the synthetic control fit. Raw synthetic-control frames and raw weight matrices are not persisted.
  • data_validation.json: Input contract report covering duplicate rows, raw outcome value checks, input/model panel missingness, finite-value checks, and any explicit handling policy.
  • assumption_validation.json: Gate-eligible parallel-trends diagnostic and advisory interference-screen report, or a skipped-status artifact when checks are disabled.
  • uplift_timeseries.png: Visual comparison of the treatment unit vs. the synthetic control over time.

Check status before interpreting lift. A partial result means the estimator returned some core quantities but uncertainty fields are incomplete. A failed result causes the CLI to exit non-zero. Also check assumption_status: skipped means interpretability checks were not run; fail or error means the causal interpretation needs review even if the effect estimate exists.

How to Run the End-to-End Pipeline

This guide explains how to orchestrate the full GeoSC workflow using the installed geosc pipeline command.

Prerequisites

  • A prepared dataset (CSV format)
  • A configuration YAML file
  • GeoSC installed

Running the Pipeline

Packaged-install example:

geosc pipeline --config /path/to/geolift_analysis_config.yaml

Source-checkout example with the shipped demo configs:

geosc pipeline --config data-config/geolift_analysis_config.yaml

Pipeline Config Behaviour

  • --config must point to one canonical stage YAML file
  • in a source checkout, GeoSC resolves the sibling canonical YAMLs from the same directory
  • GeoSC does not use a separate pipeline_config.yaml
  • built artifacts do not include the repo’s data-config/; packaged users should supply their own YAML path instead

Stage Selection

You can run partial pipelines by skipping specific stages:

  • --skip-power: Skips the power analysis stage
  • --skip-donor: Skips the donor evaluation stage
  • --only-inference: Runs only the final inference stage

Report Generation

Control report generation with:

  • --report (enabled by default)
  • --no-report

Output Directory

Specify where results should be saved:

geosc pipeline \
  --config data-config/geolift_analysis_config.yaml \
  --output-dir results/campaign_a

This will generate the following structure:

  • results/campaign_a/multicell_power_analysis/
  • results/campaign_a/multicell_donor_eval/
  • results/campaign_a/multicell_geolift_analysis/
  • results/campaign_a/geolift_pipeline_report.md
  • results/campaign_a/geolift_pipeline_report.html

For a source-tree walkthrough using the shipped demo configs, start with Quick Start.

How to Use Shapemaps

GeoSC donor 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.

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_approx_2026.geojson
  • shapemap/uk/postcode_districts_approx_2026.geojson
  • shapemap/us/dma_legacy_normalized.geojson
  • shapemap/fr/nuts3_2024.geojson
  • shapemap/de/nuts3_2024.geojson
  • shapemap/<uk|us|fr|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:

location_col_name: "postcode_district"
treatment_locations: ["SW1A", "M1"]
shapemap_file: "shapemap/uk/postcode_districts_approx_2026.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.

How to Use the Python API

While the CLI is the preferred operational path, the Python API supports programmatic control and direct-data initialization without CSV/YAML files.

Basic Usage

Packaged-install example:

from geolift import GeoLiftAnalyzer

analyzer = GeoLiftAnalyzer(
    config_path="/path/to/geolift_analysis_config.yaml",
    data_path="/path/to/input.csv",
)

results = analyzer.run_analysis()

print(f"ATT: {results['att']}")
print(f"P-value: {results['p_value']}")

Source-checkout example with the shipped demo configs:

from geolift import GeoLiftAnalyzer

analyzer = GeoLiftAnalyzer(
    config_path="data-config/geolift_analysis_config.yaml",
    data_path="data-config/synthetic_geolift_multi.csv",
)