HOME HEALTH AGENCIES & QUALITY / PYTHON + CSV

Find home-health agencies by ZIP in Python

Build a research shortlist from postal ZIPs, then add agency services and separate care-quality and patient-survey ratings.

Find agencies associated with a ZIP-code research area

You have postal ZIP codes for a healthcare market study and want to identify agencies that have served those areas, then add their services and published ratings. This example joins the ZIP relationships to the agency reference and patient-survey results.

The optional example input CSV contains two real North Carolina ZIP codes with fictional research labels, “Coastal study” and “Northern study.” The same records appear in the areas list in the Python code below. Only the study labels are invented. Agency names, service flags, ZIP relationships and ratings come from the prepared CMS data.

Download the product samples

These are small selections of the files included in the paid download, with identical filenames and columns. served_zips.csv contains every agency relationship for the two example ZIPs. agencies.csv contains the four corresponding agencies, and patient_experience.csv includes all 12 survey measures for each. Save all three files in your working folder.

Code example

The code keeps identifiers as text, preserves all agencies matching each ZIP, and selects the survey summary rating. It runs in Jupyter, IPython or a script with the Python standard library.

Paths are relative to your working folder; use from pathlib import Path; print(Path.cwd()) to check it, or supply full paths.

Python 3.10+ · Jupyter, IPython or a script
"""Find agencies that served selected postal ZIPs in the retained CMS edition."""
import csv
from pathlib import Path

DATA = Path('.')
# Fictional research labels; the ZIP codes and reference relationships are real.
areas = [
    {'area': 'Coastal study', 'zip_code': '28541'},
    {'area': 'Northern study', 'zip_code': '27853'},
]

def read_csv(name):
    with (DATA / name).open(newline='', encoding='utf-8-sig') as file:
        return list(csv.DictReader(file))

agencies = {row['agency_id']: row for row in read_csv('agencies.csv')}
ratings = {(row['agency_id'], row['measure_id']): row
           for row in read_csv('patient_experience.csv')}
relationships = read_csv('served_zips.csv')
results = []
for area in areas:
    matches = sorted((row for row in relationships
                      if row['served_zip'] == area['zip_code']),
                     key=lambda row: row['agency_id'])
    for match in matches:
        agency = agencies[match['agency_id']]
        survey = ratings[(agency['agency_id'], 'survey_stars')]
        results.append({
            **area, 'agency_id': agency['agency_id'],
            'agency_name': agency['agency_name'],
            'nursing': agency['offers_nursing'],
            'physical_therapy': agency['offers_physical_therapy'],
            'quality_stars': agency['quality_stars'] or 'unavailable',
            'survey_stars': survey['value'] or 'unavailable',
            'survey_period': survey['period_start'] + ' to ' + survey['period_end'],
            'survey_note': survey['footnote_text'] or 'none',
        })
    if not matches:
        print(area['area'] + ': no ZIP relationship in this edition')

for row in results:
    print(f"{row['area']} | {row['zip_code']} | {row['agency_id']} | {row['agency_name']}")
    print(f"  Nursing: {row['nursing']}; physical therapy: {row['physical_therapy']}; "
          f"quality stars: {row['quality_stars']}; survey stars: {row['survey_stars']}")
    print(f"  Survey period: {row['survey_period']}; survey note: {row['survey_note']}")

Analysis of the output

Coastal study | 28541 | 347002 | WELL CARE HOME HEALTH
  Nursing: Yes; physical therapy: Yes; quality stars: 5; survey stars: 5
  Survey period: 2025-01-01 to 2025-12-31; survey note: none
Coastal study | 28541 | 347333 | CENTERWELL HOME HEALTH
  Nursing: Yes; physical therapy: Yes; quality stars: 4.5; survey stars: 4
  Survey period: 2025-01-01 to 2025-12-31; survey note: none
Northern study | 27853 | 347004 | LIBERTY HOME CARE VI, LLC
  Nursing: Yes; physical therapy: Yes; quality stars: 2.5; survey stars: 5
  Survey period: 2025-01-01 to 2025-12-31; survey note: Fewer than 70 patients completed the survey. Use the scores shown, if any, with caution as the number of surveys may be too low to accurately tell how an agency is doing.
Northern study | 27853 | 347081 | NORTHAMPTON CO. HHA
  Nursing: Yes; physical therapy: Yes; quality stars: 3; survey stars: 5
  Survey period: 2025-01-01 to 2025-12-31; survey note: none

The result gives your research areas named agencies, services, and two distinct CMS ratings. ZIP 28541 is associated with Well Care and CenterWell in this edition; ZIP 27853 is associated with Liberty and Northampton County. All four report nursing and physical therapy at the agency level.

Well Care has five quality-of-patient-care stars and five survey stars. CenterWell has 4.5 and four respectively. Liberty has 2.5 quality stars and five survey stars. These columns measure different things: the first summarizes selected care-quality measures, while the second summarizes patients’ reported experiences. Neither is a substitute for the other.

Liberty’s survey result also carries CMS footnote 11: fewer than 70 patients completed the survey. Keeping that note beside its published rating matters when assessing the strength of a comparison. The nominal survey period is calendar 2025; other footnotes can warn that fewer months contributed.

A ZIP relationship means the agency served at least one patient there during the source collection period. CMS does not provide the exact ZIP-table collection dates in these retained files. It does not guarantee current availability, willingness to accept patients, or that each agency-level service was offered in each ZIP. This is a research shortlist to investigate, not a provider recommendation.

Using the full dataset

Extract the purchased ZIP and set DATA to its directory. Replace areas with your records, or read a CSV containing area and zip_code. Preserve leading zeros. A ZIP can return several agencies, and an agency can appear in several areas; keep both identifiers when counting or exporting relationships.

The full download includes 12,460 agencies, 565,608 agency-to-ZIP relationships across 34,842 distinct ZIP codes, 224,280 quality observations and 149,520 patient-experience observations. The additional quality_measures.csv supplies the underlying care measures, reporting periods, numerators, denominators, published bounds and footnotes. Select one measure_id before joining if you need one observation per agency.

A service flag of - means unavailable, not “No.” Numerical blanks have explicit statuses. The agency’s office ZIP is different from its served ZIPs, and neither should be treated as a Census ZCTA or county FIPS. Our hospital and nursing-home references support related provider research; their ratings use different definitions.

Sources and versions

This edition uses CMS files released July 15, 2026: agencies, served ZIPs, quality periods, HHCAHPS results and survey periods. The original files are freely available from CMS.

The OASIS measures cover October 2024–September 2025, the survey covers January–December 2025, and claims/spending measures have their own intervals. Quality stars combine underlying measures and are not assigned one shared reporting period. ACD captured the source files October 18, 2026 and packaged this release on 2026-10-18 UTC. See the source and preparation record for the complete scope and version policy.

Example checked October 18, 2026 against both these samples and the complete purchased files. Source and processing records, sample checksums · Expected result CSV. Independent preparation; no agency endorsement.