1. 地质矢量数据批处理概述
在地质调查与矿产勘查工作中,矢量数据是最常见的一类空间资料:地质图图幅、构造线、断层、岩体边界、矿点、化探采样点、钻孔孔位、剖面线等,几乎都以点、线、面要素的形式组织在 Shapefile、GeoPackage、GeoJSON 或 FileGDB 中。单个图幅的数据量也许不大,但一个项目区往往横跨数十个标准图幅,一个省域数据库可能包含上千个图层文件。当需要统一坐标系、统一属性字段、批量裁剪、批量合并、批量统计时,逐个人工打开处理既不现实,也极易出错。这正是"批处理"要解决的问题。
地质矢量数据的几个典型特点
理解批处理的设计,先要理解被处理对象的"脾气"。地质矢量数据通常具备以下特征:
- 多源异构:同一区域的资料可能来自不同比例尺的填图成果、不同单位提交的数据库、不同年代的归档文件,字段命名、编码体系、几何精度都不一致。
- 坐标系混杂:常见的有北京54、西安80、CGCS2000 以及各类地方独立坐标系,还夹杂着地理坐标(经纬度)与投影坐标(米)两种表达,直接叠加会出现位置偏移。
- 几何质量参差:存在自相交面、悬挂节点、重复要素、空几何、微小碎片面等,这些在单文件检查时容易漏看,批量处理时会被放大。
- 属性结构不统一:同样是断层,有的用
NAME,有的用名称,有的用FC_NAME;岩性编码有的用国标代码,有的用内部编号。 - 文件组织有规律:多数情况下按图幅号、按行政区、按矿种分目录存放,这种规律性正是批量脚本可以依赖的入口。
这些特点决定了批处理不是"写个循环跑一遍"那么简单,而是要先建立统一的处理契约:输入是什么、输出到哪里、坐标系统一成什么、字段如何映射、异常要素如何记录。
批处理的典型应用场景
结合地质业务,批处理最常出现在以下几类任务中:
一是数据入库前的标准化。 把几十个图幅的 Shapefile 统一转换为 GeoPackage,统一坐标系为 CGCS2000 3 度带投影,统一字段名与字段类型,剔除空几何与重复要素。这类任务规则明确、重复度高,最适合脚本化。
二是按范围批量裁剪与提取。 给定一个矿区范围或行政区边界,从全量数据中裁出范围内的地层、断层、矿点,并分别输出为独立文件。若涉及上百个图层,手工裁剪几乎不可行。
三是批量空间统计。 统计每个图幅内各类地质体的面积、断层总长度、矿点密度,输出为表格供后续制图或分析使用。这类任务的关键是保证每个文件的统计口径完全一致。
四是批量格式转换与成果分发。 将内部 GeoPackage 按需导出为 Shapefile、GeoJSON 或 KML,供不同平台使用,同时控制字段裁剪与编码。
五是批量质量检查。 遍历所有图层,检查几何有效性、坐标系是否缺失、字段是否齐全、要素数是否为零,生成检查报告。
GeoPandas 在批处理中的角色
GeoPandas 的核心价值在于把"空间数据"变成"可以直接用 Python 操作的表"。它基于 pandas 的 DataFrame 扩展出 GeoDataFrame,几何列以 Shapely 几何对象存储,读写依赖 Fiona 或 Pyogrio,空间运算依赖 Shapely 与 PyGEOS/Shapely 2.x,投影转换依赖 pyproj。对批处理而言,这意味着三件事:
- 文件遍历与数据读取可以统一成一条流水线。 用
pathlib.Path.rglob("*.shp")收集文件,用gpd.read_file()逐个读入,得到结构一致的 GeoDataFrame 列表。 - 属性处理与空间处理在同一对象上完成。 字段重命名、类型转换、条件筛选用 pandas 语法;裁剪、相交、缓冲、投影转换用 GeoPandas 方法,不需要在多个工具间来回导出导入。
- 结果可以批量落盘并附带日志。 每个文件的处理结果、要素数变化、异常信息都能记录成表,形成可追溯的处理台账。
下面这张图概括了批处理流水线中各环节的输入、处理与输出关系,以及 GeoPandas 所处的位置:
为什么选 GeoPandas 而不是逐个工具操作
与 ArcGIS 的模型构建器或 QGIS 的批处理界面相比,GeoPandas 的优势不在于"能处理",而在于"能表达复杂规则"。模型构建器擅长固定流程的重复执行,但一旦遇到"字段名不一致时按映射表重命名""坐标系缺失时按图幅号推断""几何无效时先修复再统计"这类带判断的逻辑,图形化工具就会变得笨重。而 GeoPandas 里这些就是普通的 Python 条件分支和字典查找,规则可以写成配置,异常可以捕获并记录。
另一个实际优势是可复现。批处理脚本本身就是处理规范:坐标系目标、字段映射表、容差参数、输出命名规则全部写在代码或配置文件中,换一个人、换一台机器,只要环境一致,结果就一致。这对地质数据入库这类需要长期维护的工作尤为重要。
一个最小可用的批处理骨架
下面这段示例代码演示了批处理的基本结构,参数与路径均为教学示例,实际使用时需替换为真实数据:
from pathlib import Path
import geopandas as gpd
import pandas as pd
SRC = Path("./raw_layers") # 示例输入目录
DST = Path("./standardized") # 示例输出目录
DST.mkdir(exist_ok=True)
TARGET_CRS = "EPSG:4547" # 示例:CGCS2000 3度带投影
FIELD_MAP = {"名称": "NAME", "FC_NAME": "NAME", "岩性": "LITHO"}
records = []
for shp in sorted(SRC.rglob("*.shp")):
try:
gdf = gpd.read_file(shp)
if gdf.crs is None:
records.append({"file": shp.name, "status": "缺少坐标系"})
continue
gdf = gdf.to_crs(TARGET_CRS)
gdf = gdf.rename(columns={k: v for k, v in FIELD_MAP.items() if k in gdf.columns})
gdf = gdf[~gdf.geometry.is_empty & gdf.geometry.notna()]
out = DST / f"{shp.stem}.gpkg"
gdf.to_file(out, driver="GPKG")
records.append({"file": shp.name, "status": "成功", "count": len(gdf)})
except Exception as e:
records.append({"file": shp.name, "status": f"失败: {e}"})
pd.DataFrame(records).to_csv(DST / "process_log.csv", index=False, encoding="utf-8-sig")
这段代码体现了批处理的几个关键约定:目标坐标系集中定义、字段映射用字典表达、空几何在写出前剔除、每个文件的处理结果写入台账而不是直接打印。运行结束后,process_log.csv 中"成功/失败/缺少坐标系"的分布就是判断整批任务是否达标的直接依据——如果失败集中在某几个图幅,通常说明这些文件的字段结构或几何类型与预期不符,需要单独排查,而不是重跑整批。