如何补全OSM提取的瑞士学校数据中缺失的addr:city/addr:postcode标签?
处理瑞士OSM学校数据缺失地址字段的方案
问题背景
我使用包含瑞士OpenStreetMap数据的.pbf文件,通过以下Osmium命令提取所有带amenity=school,college标签的条目:
osmium tags-filter switzerland-exact.osm.pbf nwr/amenity=school,college \ -o schools-in-switzerland.osm.pbf
将数据导出为JSON后用Python脚本处理,按addr:city→city、addr:postcode→postcode的规则转换格式,但部分学校缺失city或postcode字段。需要在提取或处理环节补全这些缺失标签,不局限于Osmium工具。
解决方案
1. 反向地理编码补全(Python处理阶段)
利用学校的经纬度坐标,通过OSM的地理编码服务反向查询所属城市和邮编,适合数据量不大的场景:
import json import requests def fetch_address(lat, lon): # 调用Nominatim反向地理编码接口,建议设置自定义User-Agent url = f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json&addressdetails=1" resp = requests.get(url, headers={"User-Agent": "SchoolDataTool/1.0"}) if resp.status_code != 200: return {} addr = resp.json().get('address', {}) # 适配不同层级的行政名称(城市/镇/村) return { 'city': addr.get('city') or addr.get('town') or addr.get('village'), 'postcode': addr.get('postcode') } # 读取导出的学校JSON数据 with open('schools.json', 'r') as f: school_list = json.load(f) # 遍历补全缺失字段 for school in school_list: if not school.get('city') or not school.get('postcode'): lat, lon = school.get('lat'), school.get('lon') if lat and lon: addr_data = fetch_address(lat, lon) if addr_data.get('city') and not school['city']: school['city'] = addr_data['city'] if addr_data.get('postcode') and not school['postcode']: school['postcode'] = addr_data['postcode'] # 保存补全后的数据 with open('schools_complete.json', 'w') as f: json.dump(school_list, f, indent=2)
提示:数据量较大时,建议部署本地Nominatim实例,避免在线请求的速率限制。
2. 空间关联行政边界数据(预处理阶段)
先提取瑞士的行政边界数据,再通过空间匹配补全地址,适合批量处理:
步骤1:提取行政边界
# 提取admin_level=8(对应城市层级)和带postal_code标签的边界数据 osmium tags-filter switzerland-exact.osm.pbf r/admin_level=8 r/postal_code \ -o switzerland-city-boundaries.osm.pbf
步骤2:用Geopandas做空间连接
import geopandas as gpd # 读取学校点数据和行政边界多边形数据 schools = gpd.read_file('schools-in-switzerland.osm.pbf', layer='points') boundaries = gpd.read_file('switzerland-city-boundaries.osm.pbf', layer='multipolygons') # 空间匹配:找到每个学校所在的行政区域 merged = gpd.sjoin(schools, boundaries, how='left', predicate='within') # 优先保留原地址标签,缺失时用行政边界的信息补全 merged['city'] = merged.apply(lambda x: x['addr:city'] if x['addr:city'] else x['name'], axis=1) merged['postcode'] = merged.apply(lambda x: x['addr:postcode'] if x['addr:postcode'] else x['postal_code'], axis=1) # 保存补全后的OSM数据 merged.to_file('schools_with_full_address.osm.pbf', driver='OSM')
3. 利用OSM关系继承地址
部分学校属于带地址标签的父节点(如建筑群),可通过提取关联关系补全:
步骤1:提取学校关联的关系数据
# 先导出学校的ID列表(OPL格式) osmium tags-filter switzerland-exact.osm.pbf nwr/amenity=school,college --output-format=opl > school-ids.opl # 根据ID提取关联的关系数据 osmium getid switzerland-exact.osm.pbf -i school-ids.opl --relations -o school-relations.osm.pbf
步骤2:Python解析关系补全地址
在脚本中解析关系数据,提取父节点的addr:city和addr:postcode标签,补全对应学校的缺失字段。
内容的提问来源于stack exchange,提问作者patwis
相关产品推荐
相关产品推荐

