3. 点数据清洗实战
环境监测点数据是环境质量评价、污染溯源和空间插值的基础。无论是空气质量自动监测站,还是地表水、地下水采样点,在进入GIS分析或数据库之前,往往来自不同年代、不同单位、不同采集方式,存在坐标系统不统一、点位重复、坐标偏移、属性缺失和格式混乱等问题。本节以一批假想的监测点数据为例,完整走一遍点数据清洗的关键环节,重点讲清每一步“判断什么、怎么处理、处理到什么程度算合格”。
一、先看清数据:字段结构与问题诊断
假设我们拿到一份名为 monitor_points.csv 的点位清单,包含空气质量监测点和水质采样点两类对象,主要字段有:点位编号 site_id、点位名称 site_name、类型 site_type、经度 lon、纬度 lat、坐标系统 crs、监测指标 parameter、所属行政区 district、建站年份 year。示例数据中,部分点位 crs 标注为 WGS84,部分标注为 CGCS2000,还有几条为 GCJ02;个别点位经纬度明显落在研究区之外;少数点位 district 为空;点位名称存在“XX站”“XX监测站”“XX站(空气)”等多种写法。这些问题正是清洗要解决的对象。
诊断阶段建议先做三件事:一是统计各字段的空值率与取值分布,二是把点位按经纬度快速投到地图上目视检查,三是核对 site_id 是否唯一。目视检查非常关键,很多异常坐标在表格里看不出来,一上图就暴露为“飞点”。
二、坐标系统一:先明确目标坐标系
坐标系统一不是把所有点“改成同一个标签”,而是把坐标数值真正转换到同一参考框架下。本课程约定:分析底图采用 CGCS2000 地理坐标系,单位为度。因此处理原则是:CGCS2000 点位保持不变;WGS84 点位在一般环境监测精度要求下可视为与 CGCS2000 基本一致,直接沿用并统一标注;GCJ02(火星坐标)点位必须做偏移纠正,不能简单改标签。
GCJ02 转 WGS84 没有精确解析解,工程上常用迭代逼近。下面给出一个可运行的 Python 示例,采用公开的坐标偏移算法思路,迭代若干次使结果收敛(示例参数与结果仅用于教学演示):
import math
a = 6378245.0
ee = 0.00669342162296594323
def _transform_lat(x, y):
ret = -100.0 + 2.0*x + 3.0*y + 0.2*y*y + 0.1*x*y + 0.2*math.sqrt(abs(x))
ret += (20.0*math.sin(6.0*x*math.pi) + 20.0*math.sin(2.0*x*math.pi)) * 2.0/3.0
ret += (20.0*math.sin(y*math.pi) + 40.0*math.sin(y/3.0*math.pi)) * 2.0/3.0
ret += (160.0*math.sin(y/12.0*math.pi) + 320*math.sin(y*math.pi/30.0)) * 2.0/3.0
return ret
def _transform_lon(x, y):
ret = 300.0 + x + 2.0*y + 0.1*x*x + 0.1*x*y + 0.1*math.sqrt(abs(x))
ret += (20.0*math.sin(6.0*x*math.pi) + 20.0*math.sin(2.0*x*math.pi)) * 2.0/3.0
ret += (20.0*math.sin(x*math.pi) + 40.0*math.sin(x/3.0*math.pi)) * 2.0/3.0
ret += (150.0*math.sin(x/12.0*math.pi) + 300.0*math.sin(x/30.0*math.pi)) * 2.0/3.0
return ret
def gcj02_to_wgs84(lon, lat):
dlon, dlat = lon, lat
for _ in range(10):
tlat = _transform_lat(dlon - 105.0, dlat - 35.0)
tlon = _transform_lon(dlon - 105.0, dlat - 35.0)
radlat = lat / 180.0 * math.pi
magic = 1 - ee * math.sin(radlat)**2
sqrtmagic = math.sqrt(magic)
tlat = (tlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * math.pi)
tlon = (tlon * 180.0) / (a / sqrtmagic * math.cos(radlat) * math.pi)
dlat = lat - tlat
dlon = lon - tlon
return round(dlon, 6), round(dlat, 6)
转换后应保留原始坐标字段(如 lon_raw、lat_raw)以便回溯,并新增 crs_std 字段统一写为 CGCS2000。判断转换是否合理的经验方法是:转换前后位移量一般在数百米量级,若某点位移达到数公里,说明原始标注的坐标系可能本身就错了,需要回到数据源核实。
三、重复点识别与异常坐标修正
重复点有两种:一是 site_id 完全相同的记录重复,直接去重保留最新记录即可;二是编号不同但空间位置几乎重合的点,需要按距离阈值判断。环境监测点通常有最小间距要求,可设阈值如 50 米:两两计算球面距离,小于阈值的视为疑似重复,再结合点位名称、类型、监测指标人工确认。若确属同一物理点位的重复录入,保留属性更完整的一条,并把另一条的编号记入备注字段。
异常坐标的识别要结合业务范围。以某市为例,若研究区经度范围约为 116.0~116.8、纬度约为 39.6~40.2,则落在范围外的点即为可疑点。常见成因包括:经纬度写反、小数点错位、误用了投影坐标数值(如把米制坐标填进经纬度字段)、录入时多打一位数字。修正时优先回查原始台账或监测报告;无法回查的,可依据点位名称中的地址信息重新定位,并在 coord_flag 字段标注“已修正”或“待核实”,绝不能默默改数。
四、缺失属性补全与格式标准化
属性补全要区分“可推导”和“不可推导”。district 缺失时,可用点位坐标与行政区划面做空间叠加,取所在面要素的区县名称回填,这是可靠的空间派生;site_type 缺失时,可根据 site_name 中的“空气”“水质”“断面”等关键词规则推断,并标注推断来源;而 year(建站年份)属于事实性属性,无法从坐标推导,应保留为空并列入待补清单,不能随意填默认值。
格式标准化包括:点位名称统一去除多余空格与括号后缀,建立“标准名—别名”对照;site_id 统一为“类型前缀+行政区代码+序号”的规则,如 AQ-1101-001、WQ-1101-003;经纬度统一保留 6 位小数;监测指标统一为规范代码(如 PM2.5、PM10、O3、COD、NH3-N);空值统一用空字符串而非“无”“N/A”“-9999”等混用写法。
五、结果验证与交付物
清洗完成后不能只看表格“顺眼”,要做三项验证。第一,把清洗后的点位重新上图,与行政区划、河流或路网底图叠加,检查点位是否落在合理位置,尤其关注修正过的点和补全了行政区的点。第二,统计清洗前后记录数、重复删除数、坐标修正数、属性补全数,形成清洗日志,做到每一步可追溯。第三,抽查若干点位,用点位名称在原始台账中反查,确认坐标与属性对应关系没有错位。
建议交付一份可直接使用的点位清洗记录表,字段如下(示例值仅作格式演示):
| site_id | 标准名称 | 类型 | lon_std | lat_std | crs_std | coord_flag | district | 补全来源 |
|---|---|---|---|---|---|---|---|---|
| AQ-1101-001 | 城北空气监测站 | 空气 | 116.412300 | 39.931200 | CGCS2000 | 原始 | 城北区 | 原始记录 |
| AQ-1101-002 | 工业园空气监测站 | 空气 | 116.503800 | 39.887600 | CGCS2000 | GCJ02已纠正 | 工业园 | 空间叠加 |
| WQ-1101-003 | 东河断面采样点 | 水质 | 116.455100 | 39.902400 | CGCS2000 | 坐标已修正 | 东河区 | 回查台账 |
| WQ-1101-004 | 南湖采样点 | 水质 | 116.621700 | 39.845900 | CGCS2000 | 原始 | 南湖区 | 原始记录 |
crs 字段直接写成 CGCS2000,坐标数值却未纠正,导致点位整体偏移数百米。这类错误在单点检查时很难发现,但会系统性影响后续空间插值和缓冲区分析,必须通过转换前后位移量统计来拦截。完成上述步骤后,这批点位数据才具备进入属性联接、空间分析与制图的条件。清洗的价值不在于把数据“改漂亮”,而在于让每一个坐标、每一个属性都有来源、有判断、有记录,使后续分析结论建立在可信的数据基础之上。