Improve address matching

This commit is contained in:
zyphlar
2026-02-25 10:25:49 -08:00
parent ea3e4ca098
commit bdaafd85ef
3 changed files with 168 additions and 289 deletions
+54 -13
View File
@@ -14,6 +14,7 @@ Usage:
import argparse
import json
import os
import re
import shutil
import sys
import zipfile
@@ -374,10 +375,41 @@ out geom;"""
return processed_gdf
def _normalize_street_name(self, street: str) -> str:
"""
Normalize street names for better matching.
Handles common abbreviation and formatting differences between county and OSM data.
"""
if not street or street == 'nan':
return ''
street = street.strip()
# Convert to lowercase for comparison
street_lower = street.lower()
# Normalize State Road variations
street_lower = re.sub(r'\bstate road\b', 'sr', street_lower)
street_lower = re.sub(r'\bstate route\b', 'sr', street_lower)
# Normalize County Road variations
street_lower = re.sub(r'\bcounty road\b', 'cr', street_lower)
street_lower = re.sub(r'\bc\b', 'cr', street_lower) # "C 44a" -> "cr 44a"
# Normalize County Road number formatting: "109d 1" -> "109d-1", "109d-1" stays same
# This handles both space and hyphen separators
street_lower = re.sub(r'\b(cr\s+\d+[a-z])\s+(\d+)', r'\1-\2', street_lower)
street_lower = re.sub(r'\b(cr\s+\d+[a-z])-(\d+)', r'\1-\2', street_lower)
# Remove extra spaces
street_lower = re.sub(r'\s+', ' ', street_lower).strip()
return street_lower
def compare_addresses(self, local_file: str, osm_file: str) -> Tuple[List[Dict], List[Dict], List[Dict]]:
"""
Compare local and OSM address data.
Returns:
Tuple of (new_addresses, existing_addresses, removed_addresses)
"""
@@ -435,19 +467,28 @@ out geom;"""
local_house_num = str(local_row.get('addr:housenumber', ''))
osm_house_num = str(osm_row.get('addr:housenumber', ''))
# Check street name match (required)
local_street = str(local_row.get('addr:street', '')).strip().lower()
osm_street = str(osm_row.get('addr:street', '')).strip().lower()
street_match = (local_street == osm_street and local_street != '' and local_street != 'nan')
# Check street name match (required) - use normalization for better matching
local_street = self._normalize_street_name(str(local_row.get('addr:street', '')))
osm_street = self._normalize_street_name(str(osm_row.get('addr:street', '')))
street_match = (local_street == osm_street and local_street != '')
# Check unit match (only if both have units specified)
# Check unit match - if either has a unit, both must match
local_unit = local_row.get('addr:unit')
osm_unit = osm_row.get('addr:unit')
# Unit matches if: (1) both are None/null, OR (2) both have values and they're equal
unit_match = True
if local_unit is not None and pd.notna(local_unit) and osm_unit is not None and pd.notna(osm_unit):
# Determine if each side has a unit
local_has_unit = local_unit is not None and pd.notna(local_unit) and str(local_unit).strip() != ''
osm_has_unit = osm_unit is not None and pd.notna(osm_unit) and str(osm_unit).strip() != ''
if local_has_unit and osm_has_unit:
# Both have units - they must match
unit_match = (str(local_unit).strip().lower() == str(osm_unit).strip().lower())
elif local_has_unit or osm_has_unit:
# One has unit, other doesn't - no match
unit_match = False
else:
# Neither has unit - match
unit_match = True
# Only consider as potential match if house numbers, street, and unit all match
if (local_house_num == osm_house_num and
@@ -500,10 +541,10 @@ out geom;"""
local_house_num = str(local_row.get('addr:housenumber', ''))
osm_house_num = str(osm_row.get('addr:housenumber', ''))
# Check street name match (required)
local_street = str(local_row.get('addr:street', '')).strip().lower()
osm_street = str(osm_row.get('addr:street', '')).strip().lower()
street_match = (local_street == osm_street and local_street != '' and local_street != 'nan')
# Check street name match (required) - use normalization for better matching
local_street = self._normalize_street_name(str(local_row.get('addr:street', '')))
osm_street = self._normalize_street_name(str(osm_row.get('addr:street', '')))
street_match = (local_street == osm_street and local_street != '')
# Check unit match (only if both have units specified)
local_unit = local_row.get('addr:unit')