Medallion Architecture · Layer 02

🥈

Silver Layer

I cleaned, typed, validated, and standardized every Bronze table into production-ready Silver tables. This is where CDC suppression flags get decoded, column names align across datasets, and state abbreviations are standardized for joins.

8Notebooks
0Null Violations
51States Covered
1.98MHealth Violations
Bronze Silver Gold Analytics Machine Learning

What the Silver Layer Does

The Silver layer is the cleaning and standardization layer. I apply explicit type casting, handle suppressed/null values from CDC and USDA data, rename columns for consistency across datasets, and add derived columns that simplify downstream analytics.

Key transformations include: filtering out CDC WONDER Total rollup rows (keeping only year-level data), adding state abbreviation lookups via broadcast joins so all datasets share a common join key, flagging low-coverage AQI counties with fewer than 50 monitoring days, and normalizing SDWIS state codes from mixed FIPS/abbreviation format to clean 2-letter codes.

Every Silver notebook ends with a data quality summary — row count, column count, and null counts per column — to validate that the cleaning was successful before promoting data to Gold.

Silver Cleaning Notebooks

01
Cancer Mortality Cleaning
01_clean_cancer_mortality.py

Filters CDC WONDER Total rollup rows, casts all columns to correct types, renames state columns for consistency, adds state abbreviations via broadcast join. Zero nulls across all 8 columns — the cleanest Silver table in the project.

306 rowsZero nullsState abbreviation join
02
Cancer Incidence Cleaning
02_clean_cancer_incidence.py

Same pattern as mortality but handles the plural "States"/"States Code" column names from the CDC incidence export. Includes a cross-check join between incidence and mortality Silver tables revealing the mortality-to-incidence ratio by state.

1,218 rows1999–2022Cross-dataset join
03
Air Quality Cleaning
03_clean_air_quality.py

Fixes the column starting with a number (90th_percentile_aqi → percentile_90_aqi), removes non-US entries (Canada, Mexico, territories), fixes DC casing mismatch, flags low-coverage counties, and adds EPA AQI category labels.

24,083 rowsLow-coverage flagAQI categories
04
Chronic Disease Cleaning
04_clean_chronic_disease.py

Filters 398K rows to 7 relevant topics, keeps only Overall stratification rows, uses a window function to prefer Age-Adjusted Prevalence over Crude Prevalence, and flags suppressed values (DataValueFootnoteSymbol = '*').

8,759 rows7 topics · 50 questionsAge-adjusted preference
05
SDWIS Water Quality Cleaning
05_clean_sdwis_water_quality.py

Filters 15.3M violations to 1.98M health-based violations only, normalizes mixed FIPS/abbreviation state codes, filters to active water systems, and adds human-readable water source and system type descriptions.

1.98M violationsMCL + TT filtersFIPS normalization
06
NPDES / CAFO Cleaning
06_clean_npdes_cafo.py

Identifies CAFO facilities via NAICS 112xxx codes, converts the '303(D) Listed' impaired waters flag to a boolean, joins permit status information, and adds livestock type descriptions from NAICS code mappings.

5,845 CAFOs37 statesImpaired waters flag
07
Food Environment Cleaning
07_clean_food_environment.py

Joins the variable list dictionary to add human-readable descriptions to each indicator code, pads FIPS codes to 5 characters for county-level joins, and removes negative values caused by zero-population county denominators.

957,753 rowsZero nulls3,157 counties
08
USDA Livestock Cleaning
08_clean_usda_livestock.py

Re-reads the raw file directly with the correct tab delimiter (bypassing the broken Bronze table), filters to Animals & Products sector, handles USDA suppression codes (D), (Z), (H) as nulls, and cleans comma-formatted numeric values.

940,424 rows46 commodities12.6% suppressed