Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
44d036e
Update CDC500 state query to use new TimeSeries and Observation tables
shvngisingh Aug 10, 2026
ebc79b7
Update scripts/us_cdc/cdc500_state/process.py
shvngisingh Aug 10, 2026
fdcdbb5
Address review comments: optimize joins, add provenance filters, and …
shvngisingh Aug 27, 2026
d2d7610
Address code review findings for CDC500 state aggregation: fix Census…
shvngisingh Aug 31, 2026
3415550
Add validation_config.json, update manifest, add tMCF units and guard…
shvngisingh Aug 31, 2026
dbc6962
Address code review feedback on CDC500 state aggregation: update READ…
shvngisingh Sep 1, 2026
74dd551
Address code review findings: remove unused pandas import, add datafr…
shvngisingh Sep 2, 2026
f7d2dfc
Return True on successful process completion and update unit tests
shvngisingh Sep 2, 2026
475be72
Restrict entity resolution to city-level places and restore source_fi…
shvngisingh Sep 2, 2026
7f95d76
Merge branch 'master' into cdc500_states_query
shvngisingh Sep 8, 2026
da5e51c
Address code review feedback on CDC500 state aggregation
shvngisingh Sep 8, 2026
b69963e
Address code review findings for CDC500 state aggregation
shvngisingh Sep 8, 2026
81294e4
Remove check_statvar_max_dates and check_deleted_records_percent from…
shvngisingh Sep 9, 2026
c4067f9
Address review findings: add deterministic last_update_timestamp dedu…
shvngisingh Sep 9, 2026
e9e14fe
Restore source_files in CDC500 state manifest.json
shvngisingh Sep 9, 2026
0aa9e78
Address code review feedback on CDC500 state aggregation
shvngisingh Sep 10, 2026
5bdc375
Harden process.py, test suite, and validation config
shvngisingh Sep 10, 2026
65f4cb0
Polish README artifact links and remove trailing EOF newline in test …
shvngisingh Sep 10, 2026
7a9c9a7
Fix line length in validation_config.json to conform to PEP 8
shvngisingh Sep 10, 2026
9e18e01
Clean up redundant SQL filter and expand unit test assertions
shvngisingh Sep 10, 2026
9c1f0f3
Remove LENGTH(O.entity1) = 13 filter from CDC500 state query
shvngisingh Sep 15, 2026
628b6c5
Add AND (LENGTH(O.entity1) = 13 OR O.entity1 = 'geoId/15003') filter …
shvngisingh Sep 15, 2026
356af44
Fix Hawaii geoId/15003 double-counting, add error logging, right-size…
shvngisingh Sep 15, 2026
5ae139b
Use explicit WHERE filter for Hawaii geoId/15003 in CDC500 state query
shvngisingh Sep 15, 2026
d23ffa0
Address code review findings: add defensive SQL NULL checks, simplify…
shvngisingh Sep 15, 2026
0585f03
Address review feedback: harden SQL NULL/empty checks, simplify query…
shvngisingh Sep 16, 2026
5cf8218
Remove redundant cleaned_csv from source_files in manifest.json
shvngisingh Sep 16, 2026
eecd9cc
Add BigQuery timeout and project logging in process.py; expand DuckDB…
shvngisingh Sep 18, 2026
cea521c
Refine validation description and clarify CDC PLACES lineage in README
shvngisingh Sep 18, 2026
f900d1e
Allow 100% deletion threshold for TMCF unit/scalingFactor migration a…
shvngisingh Sep 18, 2026
4cd11d9
Address CRA findings: simplify regexes, add logging.fatal in main, re…
shvngisingh Sep 21, 2026
aca4c39
Address P3 review polish: move client init inside try in main, add ce…
shvngisingh Sep 21, 2026
ca314c3
Shorten SQL_VALIDATOR query in validation_config.json to satisfy 100-…
shvngisingh Sep 21, 2026
98149ab
Address review findings: restore cohort-specific date freshness check…
shvngisingh Sep 21, 2026
5ffb554
Enhance date parsing robustness in validation_config and document dir…
shvngisingh Sep 21, 2026
4b0ddfe
Address review findings from GPaste 4586740472479744: bump disk limit…
shvngisingh Sep 22, 2026
2b76416
Address review findings: format SQL query in validation_config and cl…
shvngisingh Sep 22, 2026
98e36e9
Cast MaxDate to VARCHAR before SUBSTR in validation_config.json SQL v…
shvngisingh Sep 22, 2026
e1f29f7
Use spanner_dc_graph_prod_snap_latest snapshot dataset in CDC 500 sta…
shvngisingh Oct 5, 2026
9bd3f31
Address review findings: eliminate manual baseline copy, validate ato…
shvngisingh Oct 6, 2026
67ade9a
Read provenance and measurementMethod from TimeSeries.facet JSON column
shvngisingh Oct 8, 2026
64bf51c
Address PR review comments in process.py
shvngisingh Oct 12, 2026
589d575
Add remaining SQL review comments and DataCommonsAggregate fallback
shvngisingh Oct 12, 2026
d14ea1f
Restore original 2021 copyright year in process.py
shvngisingh Oct 15, 2026
8250582
Remove check_statvar_max_dates rule from validation_config.json
shvngisingh Oct 16, 2026
34f717e
Merge branch 'master' into cdc500_states_query
shvngisingh Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 101 additions & 11 deletions scripts/us_cdc/cdc500_state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,127 @@ Author: Padma Gundapaneni @padma-g
## Table of Contents
1. [About the Dataset](#about-the-dataset)
1. [Overview](#overview)
2. [Data Sources and Tables](#data-sources-and-tables)
3. [Aggregation Methodology](#aggregation-methodology)
2. [About the Import](#about-the-import)
1. [Artifacts](#artifacts)
2. [Import Procedure](#import-procedure)
3. [Production Rollout / Deployment SOP](#production-rollout--deployment-sop)
4. [Troubleshooting](#troubleshooting)

## About the Dataset

### Overview
The state level data is aggragated from city level data coming from CDC500 import.
The state-level dataset calculates aggregated health indicator prevalence estimates for US states from the city-level CDC 500 Cities (`CDC500`) project data, weighted by corresponding Census ACS 5-Year population counts.

To get the data for this import run:
```bash
$ python3 process.py
```
CDC PLACES (Population Level Analysis and Community Estimates) is the official successor program to the original CDC 500 Cities project, expanding health estimates across all US counties, places, and census tracts. In Data Commons, city-level data from both the historical CDC 500 Cities project (2016–2019) and ongoing CDC PLACES releases (2020–present) are ingested under provenance `dc/base/CDC500`.

### Data Sources and Tables

The aggregation script queries Google Cloud BigQuery graph tables in dataset `datcom-store.spanner_dc_graph_prod_snap_latest`:

1. **`TimeSeries`**:
- **CDC 500 Series**: Identifies CDC 500 Statistical Variables (`JSON_VALUE(facet.provenance) = 'dc/base/CDC500'` and `variable_measured LIKE 'Percent_%'`) and extracts their measurement methods (`JSON_VALUE(facet.measurementMethod)`). It maps each percentage health metric to its appropriate denominator demographic cohort StatVar (e.g., `Count_Person_18OrMoreYears`, `Count_Person_18To64Years`, `Count_Person_65OrMoreYears`, `Count_Person`, etc.).
- **Census ACS 5-Year Series**: Filters and joins population counts from Census ACS 5-Year Survey (`JSON_VALUE(facet.provenance) = 'dc/base/CensusACS5YearSurvey'`).

2. **`Observation`**:
- **Health Indicator Percentages**: Fetches city-level percentage values (`value AS percent`), observation dates (`date`), and city geoIds (`entity1 LIKE 'geoId/%'`) for CDC 500 StatVars. To prevent double-counting Oahu/Honolulu County population in years where 13-character Census Designated Places (`geoId/15XXXXX`) are published (2017–2022), `geoId/15003` is explicitly filtered in the `WHERE` clause to include only years `<= '2016'` and `'2017'` county-only indicators (excluding the four 2017 blood pressure and cholesterol indicators that also have 13-character CDP data).
- **City Cohort Populations**: Fetches city-level population counts (`value AS population`) for the corresponding demographic cohort StatVars.

### Aggregation Methodology

For each state, indicator StatVar, and observation date:
- City observations are joined with their corresponding demographic population counts.
- City geoIds (`geoId/XXXXXXX`) are mapped to state geoIds (`geoId/XX`) using the first 8 characters (including the prefix).
- State-level prevalence percentages are computed as a population-weighted average:

$$\text{State Percent} = \frac{\sum (\text{City Population} \times \text{City Percent})}{\sum \text{City Population}}$$

The output measurement method is prefixed with `dcAggregate/` (e.g., `dcAggregate/CrudePrevalence`).

*Note on Demographic Cohorts:* Several adult health indicators (such as `Percent_Person_Smoking`, `Percent_Person_Obesity`, `Percent_Person_WithDiabetes`) lack explicit age tokens in their DCID and intentionally fall back to `Count_Person` weighting to preserve bitwise parity with existing Data Commons baseline observations.

#### Excluded Indicators

The following age-bracketed cancer screening indicators are omitted from state-level aggregation:
- `Percent_Person_50To74Years_Female_ReceivedMammography`
- `Percent_Person_21To65Years_Female_ReceivedCervicalCancerScreening`
- `Percent_Person_21To65Years_Female_ReceivedPapSmearTest`
- `Percent_Person_50To75Years_ReceivedColorectalCancerScreening`

**Rationale**: The Census ACS 5-Year Survey does not publish single composite population StatVars for these non-standard multi-year age brackets (`50To74Years`, `21To65Years`, `50To75Years`). In the legacy query, these indicators were already silently dropped during the inner join with ACS population series. Rather than applying arbitrary proxy weights, these indicators are explicitly excluded in the query CTE, preserving full parity with the legacy pipeline while preventing unnecessary processing.

## About the Import

### Artifacts

#### Scripts
[`process.py`](https://github.com/datacommonsorg/data/blob/master//scripts/us_cdc/cdc500_state/process.py)
[`process.py`](process.py)

#### Unit Tests
[`process_test.py`](process_test.py)

#### tMCF Template
[`cdc500_state.tmcf`](cdc500_state.tmcf)

Comment thread
shvngisingh marked this conversation as resolved.
#### Validation Config
[`validation_config.json`](validation_config.json)

#### tMCFs
[`cdc500_state.tmcf`](https://github.com/datacommonsorg/data/blob/master/scripts/us_cdc/cdc500_state/cdc500_state.tmcf)
#### Manifest
[`manifest.json`](manifest.json)

### Import Procedure

#### Data Download and Processing Steps
#### Prerequisites

Ensure Google Cloud authentication is configured with access to BigQuery dataset `datcom-store.spanner_dc_graph_prod_snap_latest`:

```bash
$ gcloud auth application-default login
```

#### Running the Script

To get the data for this import run:
To run the BigQuery aggregation and write the output CSV to the default output directory (`scripts/us_cdc/cdc500_state/CDC500State_Output/CDC500State_Output.csv` when run from repository root):

```bash
$ python3 process.py
$ python3 scripts/us_cdc/cdc500_state/process.py
```

To specify a custom output directory:

```bash
$ python3 scripts/us_cdc/cdc500_state/process.py --output_dir=/path/to/output
```

To specify a GCP project and timeout (in seconds) for BigQuery jobs (if not set in ambient environment):

```bash
$ python3 scripts/us_cdc/cdc500_state/process.py --project=my-gcp-project --timeout=600
```

#### Running Unit Tests

Run the test suite using Python's `unittest` runner from the repository root:

```bash
$ python3 -m unittest scripts/us_cdc/cdc500_state/process_test.py
# or via module path:
$ python3 -m unittest scripts.us_cdc.cdc500_state.process_test
```

#### Automation

This import is automated via Data Commons Import Automation and scheduled to run weekly via Cloud Batch every Monday at 01:00 UTC (`cron_schedule: "0 1 * * 1"` in `manifest.json`).

- **Import Type**: Automated (weekly Cloud Batch cron: `0 1 * * 1`)
- **Production GCS Path**: `gs://datcom-prod-imports/scripts/us_cdc/cdc500_state/CDC500_States/`
- **Test GCS Path**: `gs://datcom-import-test/scripts/us_cdc/cdc500_state/CDC500_States/`

### Production Rollout / Deployment SOP

Adding `unit: Percent` and `scalingFactor: 100` to `cdc500_state.tmcf` standardizes observation series identity keys across the Knowledge Graph. Manual manipulation of `latest_version.txt` in production GCS is strictly prohibited per `b/548893664` and `CHK-9.3`; baseline promotion is handled strictly through validated automated pipeline executions.

### Troubleshooting

- **`ValueError: BigQuery query returned 0 rows`**: Verify ADC authentication (`gcloud auth application-default login`) and ensure read permissions on `datcom-store.spanner_dc_graph_prod_snap_latest`. Pass `--project=<gcp_project_id>` if running outside the default project.
4 changes: 3 additions & 1 deletion scripts/us_cdc/cdc500_state/cdc500_state.tmcf
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ variableMeasured: C:CDC->statvar
observationAbout: C:CDC->observation_about
observationDate: C:CDC->observation_date
value: C:CDC->percent
unit: Percent
Comment thread
shvngisingh marked this conversation as resolved.
scalingFactor: 100
measurementMethod: C:CDC->measurement_method
observationPeriod: "P1Y"
observationPeriod: "P1Y"
13 changes: 7 additions & 6 deletions scripts/us_cdc/cdc500_state/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
}
],
"resource_limits": {
"cpu": 8,
"memory": 64,
"disk": 100
"cpu": 2,
"memory": 8,
"disk": 30
},
"source_files": [
"CDC500State_Output/CDC500State_Output.csv"
"validation_config.json"
],
"cron_schedule": "0 1 * * 1"
"cron_schedule": "0 1 * * 1",
"validation_config_file": "validation_config.json"
}
]
}
}
Loading
Loading