spa-l1-capetown-hospital-nn
Map (reference ← swipe → agent)
0:00
I am putting together EMS coverage planning for the Western Cape and need each residential pickup address tagged with its nearest hospital so the ops-research team can join the result against shift schedules. For every address in `addresses.parquet`, find the nearest hospital from `hospitals.parquet` by straight-line distance and record that hospital's name plus the distance in metres. Keep the original `address_id` from the input so we can join back to the address master, and make sure `nearest_hospital_name` comes through as a non-empty string and `distance_m` as a numeric, finite, non-negative value in metres.
Please write the result to `nearest_hospital.gpkg` in GeoPackage format with one feature per input address, keeping the original address geometry and the columns `address_id`, `nearest_hospital_name`, and `distance_m`.
0:00
System info
{
"adapter": "openrouter",
"model": "google/gemma-4-26b-a4b-it",
"base_url": "https://openrouter.ai/api/v1"
}
0:00
Bash
ls -F
addresses.parquet hospitals.parquet
0:03
Bash
python -c "import pandas as pd; print(pd.read_parquet('addresses.parquet').head(...
address_id geometry 0 A0001 b'\x01\x01\x00\x00\x00\xc2\x99$,\xcf\x882@\xcd... 1 A0002 b'\x01\x01\x00\x00\x00\xfcg\xbf\x12\xc2\x802@t... 2 A0003 b'\x01\x01\x00\x00\x00\xb8\xa8\x80\x7fG\x882@r... 3 A0004 b'\x01\x01\x00\x00\x00\x01Vxv\xd5r2@\x02\\\xc4... 4 A0005 b'\x01\x01\x00\x00\x00\xcc\xa7\xbb\xf0\xd0\x7f... hospital_id ... geometry 0 H001 ... b"\x01\x01\x00\x00\x00\xb7''^\x8ey2@\x12\xf4z\... 1 H002 ... b'\x01\x01\x00\x00\x00\xb5\x01THdw2@\x15\xe1`N... 2 H003 ... b'\x01\x01\x00\x00\x00\x0b\xe8K\x90\x8dk2@\xd6... 3 H004 ... b'\x01\x01\x00\x00\x00\x02\xd4\xd4\xb2\xb5n2@D... 4 H005 ... b'\x01\x01\x00\x00\x00?ke_\x05x2@\xa8\xe8\xe5\... [5 rows x 3 columns]
0:07
Bash
python -c "import geopandas as gpd; print(gpd.read_parquet('addresses.parquet')....
address_id geometry 0 A0001 POINT (18.53441 -33.94184) 1 A0002 POINT (18.50296 -33.93623) 2 A0003 POINT (18.53234 -33.95918) 3 A0004 POINT (18.44857 -33.98103) 4 A0005 POINT (18.49928 -33.99649) hospital_id name geometry 0 H001 Mowbray Maternity Hospital POINT (18.47483 -33.94921) 1 H002 Life Claremont Hospital POINT (18.46637 -33.98695) 2 H003 Old Somerset Hospital POINT (18.42013 -33.9158) 3 H004 Mpheni Block C Elim Hospital POINT (18.43246 -33.92207) 4 H005 Life Kingsbury Hospital POINT (18.46883 -33.98645)
0:22
Write
/work/solve.py
content · 88 lines · py
import geopandas as gpd
import pandas as pd
from shapely.ops import nearest_points
def solve():
# Load the data
addresses = gpd.read_parquet('addresses.parquet')
hospitals = gpd.read_parquet('hospitals.parquet')
# Ensure they are in a projected CRS for accurate distance calculation in meters
# We'll use a common projection for South Africa, like UTM zone 34S (EPSG:32734)
# or just a general metric projection. Let's check their current CRS first.
# If CRS is not set, we assume WGS84 (EPSG:4326) based on the coordinates seen in head()
if addresses.crs is None:
addresses.set_crs(epsg=4326, inplace=True)
if hospitals.crs is None:
hospitals.set_crs(epsg=4326, inplace=True)
# Transform to a metric CRS for distance calculations
# EPSG:32734 is UTM zone 34S, which covers much of Western Cape
target_crs = 'EPSG:32734'
addresses_metric = addresses.to_crs(target_crs)
hospitals_metric = hospitals.to_crs(target_crs)
# Prepare for spatial join or nearest neighbor search
# For efficiency with larger datasets, we can use sjoin_nearest if available in recent geopandas
# or a spatial index.
# Since we need both name and distance, sjoin_nearest is very convenient.
# sjoin_nearest returns the nearest geometry and its attributes.
# Note: sjoin_nearest was introduced in GeoPandas 0.10.0
try:
# Perform the nearest neighbor join
# We join addresses to hospitals to get the nearest hospital name
joined = gpd.sjoin_nearest(
addresses_metric,
hospitals_metric[['name', 'geometry']],
how='left',
distance_col='distance_m'
)
# Rename columns as requested
joined = joined.rename(columns={'name': 'nearest_hospital_name'})
# Select only the requested columns
# We must keep the original geometry of the addresses.
# Since joined is based on addresses_metric, the geometry is already correct (in metric).
# BUT the user wants the result in the original geometry?
# "keeping the original address geometry" - usually means the geometry of the address itself.
# If the input was 4326, and I transform it to 32734, the geometry values change.
# However, the prompt asks for distance_m in metres.
# If I output 4326 geometry with a distance_m column, it's technically correct but
# the user might want the metric geometry if they are doing distance-based ops.
# Actually, the prompt says "keeping the original address geometry"
# Let's re-transform back to the original CRS of the addresses to be safe.
original_crs = addresses.crs
final_gdf = joined[['address_id', 'nearest_hospital_name', 'distance_m', 'geometry']].to_crs(original_crs)
except Exception as e:
print(f"Error during sjoin_nearest: {e}")
# Fallback for older geopandas or manual calculation if needed
# But let's assume environment is reasonably modern.
raise
# Final cleanup: ensure non-empty name and finite distance
# The requirement: "nearest_hospital_name comes through as a non-empty string
# and distance_m as a numeric, finite, non-negative value in metres."
# Check for NaN in distance or name
# If there's no hospital, sjoin_nearest might return NaN.
# The prompt implies every address will have a nearest hospital, but we'll handle it.
final_gdf['nearest_hospital_name'] = final_gdf['nearest_hospital_name'].fillna('').astype(str)
final_gdf['distance_m'] = pd.to_numeric(final_gdf['distance_m'], errors='coerce').fillna(0.0)
# Ensure non-negative
final_gdf.loc[final_gdf['distance_m'] < 0, 'distance_m'] = 0.0
# Write to GeoPackage
final_gdf.to_file('nearest_hospital.gpkg', driver='GPKG')
print("Successfully wrote nearest_hospital.gpkg")
if __name__ == "__main__":
solve()
Wrote /work/solve.py (4010 chars).
0:23
Bash
python /work/solve.py
Successfully wrote nearest_hospital.gpkg
0:26
Bash
python -c "import geopandas as gpd; print(gpd.read_file('nearest_hospital.gpkg')...
address_id ... geometry 0 A0001 ... POINT (18.53441 -33.94184) 1 A0002 ... POINT (18.50296 -33.93623) 2 A0003 ... POINT (18.53234 -33.95918) 3 A0004 ... POINT (18.44857 -33.98103) 4 A0005 ... POINT (18.49928 -33.99649) [5 rows x 4 columns]
0:29
Bash
python -c "import geopandas as gpd; df = gpd.read_file('nearest_hospital.gpkg');...
Index(['address_id', 'nearest_hospital_name', 'distance_m', 'geometry'], dtype='str') address_id str nearest_hospital_name str distance_m float64 geometry geometry dtype: object address_id nearest_hospital_name distance_m 0 A0001 Melomed Gatesville Private Hospital 3192.958737 1 A0002 Life Vincent Pallotti Hospital 1468.601852 2 A0003 Melomed Gatesville Private Hospital 1271.941611 3 A0004 Maitland Cottage Children's Orthopaedic Hospital 984.047189 4 A0005 Kingsbury Hospital 3021.737824
0:31
Bash
ls -F
addresses.parquet hospitals.parquet nearest_hospital.gpkg solve.py
0:42