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。对批处理而言,这意味着三件事:

  1. 文件遍历与数据读取可以统一成一条流水线。 用 pathlib.Path.rglob("*.shp") 收集文件,用 gpd.read_file() 逐个读入,得到结构一致的 GeoDataFrame 列表。
  2. 属性处理与空间处理在同一对象上完成。 字段重命名、类型转换、条件筛选用 pandas 语法;裁剪、相交、缓冲、投影转换用 GeoPandas 方法,不需要在多个工具间来回导出导入。
  3. 结果可以批量落盘并附带日志。 每个文件的处理结果、要素数变化、异常信息都能记录成表,形成可追溯的处理台账。

下面这张图概括了批处理流水线中各环节的输入、处理与输出关系,以及 GeoPandas 所处的位置:

地质矢量数据批处理流水线 输入:多源图层 图幅 Shapefile *.shp / *.dbf GeoPackage *.gpkg 多图层 GeoJSON *.geojson FileGDB *.gdb 参考边界 矿区范围 / 行政区 GeoPandas 批处理核心 ① 文件遍历:Path.rglob 收集图层 ② 读取:gpd.read_file → GeoDataFrame ③ 坐标统一:to_crs(CGCS2000 投影) ④ 字段映射与几何清洗 ⑤ 空间运算:裁剪 / 相交 / 统计 ⑥ 写出:to_file + 处理台账 输出:标准成果 标准化 GeoPackage 统一坐标系与字段 裁剪后专题图层 按范围 / 图幅分件 统计汇总表 面积 / 长度 / 密度 质量检查报告 空几何 / 无效面 处理日志台账 逐文件可追溯 异常要素回写台账,不中断整批任务

为什么选 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 中"成功/失败/缺少坐标系"的分布就是判断整批任务是否达标的直接依据——如果失败集中在某几个图幅,通常说明这些文件的字段结构或几何类型与预期不符,需要单独排查,而不是重跑整批。

批处理的第一原则是"先小样本验证,再全量执行"。建议先挑 2~3 个代表性图层跑通流程,确认坐标系、字段映射和输出结构无误后,再放开目录遍历。这样能把问题定位在单个文件上,而不是淹没在几百条日志里。