{"id":36969185,"url":"https://github.com/yolodex-ai/census-lookup","last_synced_at":"2026-01-13T21:03:57.295Z","repository":{"id":329117115,"uuid":"1118245649","full_name":"yolodex-ai/census-lookup","owner":"yolodex-ai","description":"Offline address-to-Census data mapping for Python with PL 94-171 and ACS support","archived":false,"fork":false,"pushed_at":"2025-12-19T16:49:57.000Z","size":359,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-04T21:18:30.137Z","etag":null,"topics":["census","demographics","geocoding","gis","python"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yolodex-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-17T13:23:03.000Z","updated_at":"2025-12-19T16:50:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/yolodex-ai/census-lookup","commit_stats":null,"previous_names":["yolodex-ai/census-lookup"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/yolodex-ai/census-lookup","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yolodex-ai%2Fcensus-lookup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yolodex-ai%2Fcensus-lookup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yolodex-ai%2Fcensus-lookup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yolodex-ai%2Fcensus-lookup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yolodex-ai","download_url":"https://codeload.github.com/yolodex-ai/census-lookup/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yolodex-ai%2Fcensus-lookup/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28399605,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["census","demographics","geocoding","gis","python"],"created_at":"2026-01-13T21:03:56.571Z","updated_at":"2026-01-13T21:03:57.290Z","avatar_url":"https://github.com/yolodex-ai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# census-lookup\n\n[![CI](https://github.com/yolodex-ai/census-lookup/actions/workflows/ci.yml/badge.svg)](https://github.com/yolodex-ai/census-lookup/actions/workflows/ci.yml)\n[![PyPI version](https://badge.fury.io/py/census-lookup.svg)](https://pypi.org/project/census-lookup/)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](https://github.com/yolodex-ai/census-lookup)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA Python library for mapping US addresses to Census data locally, without relying on rate-limited APIs. Supports Census 2020 (PL 94-171) and American Community Survey (ACS) 5-Year Estimates.\n\n## Features\n\n- **Fully offline geocoding** using TIGER Address Range files (~95% match rate)\n- **Lazy per-state data downloading** - only download data for states you need\n- **Census data at ALL geographic levels** - block, block group, tract, county, and state in a single lookup\n- **Two Census data sources**:\n  - **PL 94-171** (Redistricting Data): Population, race, housing counts at block level\n  - **ACS 5-Year Estimates**: Income, education, employment, housing characteristics at tract level\n- **Efficient batch processing** for large address lists\n- **CLI and Python API** - use from command line or in your code\n\n## Installation\n\n```bash\n# Using uv (recommended)\nuv add census-lookup\n\n# Using pip\npip install census-lookup\n```\n\n## Quick Start\n\n### CLI (no install required)\n\n```bash\n# Look up a single address (auto-downloads data as needed)\nuvx census-lookup lookup \"123 Main St, Los Angeles, CA 90012\"\n\n# Include specific census variables\nuvx census-lookup lookup \"123 Main St, Los Angeles, CA 90012\" -v P1_001N -v H1_001N\n\n# Process a batch file (use -l to set output level for CSV columns)\nuvx census-lookup batch input.csv output.csv --address-column addr -l tract\n\n# Pre-download data for states (optional - data downloads automatically)\nuvx census-lookup download CA TX NY\n\n# List available census variables\nuvx census-lookup variables\n\n# Show cache info\nuvx census-lookup info\n```\n\n### Example Output\n\n```bash\n$ uvx census-lookup lookup \"1600 Pennsylvania Avenue NW, Washington, DC 20500\" -v P1_001N\n```\n\n```json\n{\n  \"input_address\": \"1600 Pennsylvania Avenue NW, Washington, DC 20500\",\n  \"matched_address\": \"Pennsylvania Ave NW\",\n  \"latitude\": 38.898761,\n  \"longitude\": -77.035117,\n  \"match_type\": \"interpolated\",\n  \"match_score\": 0.9,\n  \"state_fips\": \"11\",\n  \"county_fips\": \"11001\",\n  \"tract\": \"11001010100\",\n  \"block_group\": \"110010101003\",\n  \"block\": \"110010101003014\",\n  \"P1_001N\": {\n    \"block\": 19.0,\n    \"block_group\": 963.0,\n    \"tract\": 2699.0,\n    \"county\": 689545.0,\n    \"state\": 689545.0\n  }\n}\n```\n\nCensus data is returned at **all geographic levels** in a single lookup. Each variable contains values aggregated at block, block group, tract, county, and state levels.\n\nWith ACS variables (median income, home value):\n\n```bash\n$ uvx census-lookup lookup \"1600 Pennsylvania Avenue NW, Washington, DC 20500\" \\\n    -v B19013_001E -v B25077_001E\n```\n\n```json\n{\n  \"...\": \"...\",\n  \"B19013_001E\": {\n    \"tract\": 72500.0\n  },\n  \"B25077_001E\": {\n    \"tract\": 485000.0\n  }\n}\n```\n\nACS variables are available at tract level and above.\n\n### Python API\n\n```python\nfrom census_lookup import CensusLookup\n\n# Initialize (first use will download data for the state)\nlookup = CensusLookup(\n    variables=[\"P1_001N\", \"H1_001N\"],  # Population, Housing units\n)\n\n# Single address lookup\nresult = await lookup.geocode(\"123 Main St, Los Angeles, CA 90012\")\nprint(f\"Block GEOID: {result.block}\")\nprint(f\"Block Population: {result.census_data['P1_001N']['block']}\")\nprint(f\"Tract Population: {result.census_data['P1_001N']['tract']}\")\n\n# Batch processing\nimport pandas as pd\ndf = pd.read_csv(\"addresses.csv\")\nresults = await lookup.geocode_batch(df[\"address\"], progress=True)\n```\n\n## Geographic Levels\n\n| Level | GEOID Length | Example |\n|-------|--------------|---------|\n| State | 2 | `06` |\n| County | 5 | `06037` |\n| Tract | 11 | `06037210100` |\n| Block Group | 12 | `060372101001` |\n| Block | 15 | `060372101001023` |\n\n## Census Variables\n\n### PL 94-171 (Redistricting Data)\n\nAvailable at **block level** and above. Includes:\n\n- **P1**: Race (total population, by race categories)\n- **P2**: Hispanic/Latino by Race\n- **P3**: Race for Population 18+ (voting age)\n- **P4**: Hispanic/Latino 18+\n- **H1**: Housing Units (total, occupied, vacant)\n\n```python\n# Use variable groups\nlookup = CensusLookup(variable_groups=[\"population\", \"housing\"])\n\n# Or specify individual variables\nlookup = CensusLookup(variables=[\"P1_001N\", \"P1_003N\", \"H1_001N\"])\n```\n\n### ACS 5-Year Estimates (American Community Survey)\n\nAvailable at **tract level** and above. Includes richer demographic data:\n\n| Category | Key Variables | Description |\n|----------|---------------|-------------|\n| **Income** | `B19013_001E`, `B19301_001E` | Median household income, per capita income |\n| **Poverty** | `B17001_001E`, `B17001_002E` | Total population, below poverty level |\n| **Education** | `B15003_022E`, `B15003_023E` | Bachelor's degree, Master's degree |\n| **Employment** | `B23025_004E`, `B23025_005E` | Employed, Unemployed |\n| **Housing** | `B25077_001E`, `B25064_001E` | Median home value, median rent |\n| **Tenure** | `B25003_002E`, `B25003_003E` | Owner-occupied, Renter-occupied |\n| **Health** | `B27010_017E`, `B27010_050E` | Employer insurance, Medicare |\n| **Commute** | `B08301_003E`, `B08301_010E` | Drove alone, Public transit |\n| **Internet** | `B28002_004E`, `B28002_013E` | Broadband access, No internet |\n| **Language** | `B16001_002E`, `B16001_003E` | English only, Spanish |\n\nOver 100+ ACS variables available. Run `uvx census-lookup variables --acs` for the full list\n\n```python\nfrom census_lookup import CensusLookup, list_acs_variable_groups\n\n# See available ACS variable groups\nprint(list_acs_variable_groups())\n\n# Use ACS variables with your lookup\nlookup = CensusLookup(\n    variables=[\"P1_001N\"],  # PL 94-171 population\n    acs_variables=[\"B19013_001E\", \"B25077_001E\"],  # Median income, home value\n    # Or use variable groups:\n    # acs_variable_groups=[\"income\", \"housing\"],\n)\n\nresult = await lookup.geocode(\"123 Main St, Los Angeles, CA 90012\")\n# PL 94-171 data available at all levels\nprint(f\"Block Population: {result.census_data['P1_001N']['block']}\")\n# ACS data available at tract level\nprint(f\"Median Income: ${result.census_data['B19013_001E']['tract']:,}\")\n```\n\n**Note**: ACS data is available at tract level and above. When you request ACS variables,\nthey will appear in the nested output with `tract` (and higher) levels populated.\n\n## Data Storage\n\nData is cached in `~/.census-lookup/`:\n\n```\n~/.census-lookup/\n├── catalog.json           # Tracks downloaded data\n├── tiger/\n│   ├── addrfeat/         # Address range features\n│   └── blocks/           # Block polygons\n└── census/\n    ├── pl94171/          # PL 94-171 data\n    └── acs5/             # ACS 5-Year data\n        └── tract/        # ACS at tract level\n```\n\nTypical storage per state: 100-300MB (TIGER + PL 94-171), plus ~10-50MB for ACS\n\n## How It Works\n\n1. **Parse address** using the `usaddress` library\n2. **Normalize street name** for TIGER matching\n3. **Match to TIGER Address Range** segment\n4. **Interpolate coordinates** along the street segment\n5. **Spatial lookup** using rtree index to find containing census block\n6. **Join census data** using DuckDB for efficient queries\n\n## Data Sources\n\nAll data is downloaded from official US Census Bureau sources:\n\n- **TIGER/Line Shapefiles**: Geographic boundaries and address ranges\n  - https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html\n  - Address Range Feature files (ADDRFEAT) for geocoding\n  - Block shapefiles for spatial lookups\n\n- **PL 94-171 Redistricting Data**: Population and housing counts\n  - https://www.census.gov/programs-surveys/decennial-census/about/rdo/summary-files.html\n  - Available at block level and above\n\n- **American Community Survey (ACS) 5-Year Estimates**: Socioeconomic data\n  - https://www.census.gov/programs-surveys/acs\n  - Available at tract level and above\n  - Accessed via Census API: https://api.census.gov\n\n## Development\n\n```bash\n# Clone and install with uv\ngit clone https://github.com/yolodex-ai/census-lookup.git\ncd census-lookup\nuv sync --all-extras\n\n# Run unit tests (fast, no network required)\nuv run pytest tests/unit -v\n\n# Run functional tests (downloads real data, slower)\nuv run pytest tests/functional -v -s\n\n# Run all tests\nuv run pytest tests/ -v\n\n# Run linting\nuv run ruff check src/\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyolodex-ai%2Fcensus-lookup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyolodex-ai%2Fcensus-lookup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyolodex-ai%2Fcensus-lookup/lists"}