3. GeoDataFrame与地质矢量数据模型
在GeoPandas中,GeoDataFrame是承载地质矢量数据的核心容器。它继承自pandas的DataFrame,因此拥有完整的属性表能力;同时额外增加了一列特殊的几何列(默认名为geometry),用于存储每个要素的空间形状。理解“属性表 + 几何列 + 坐标参考系”这三件套,是后续批量处理断层、地层、钻孔、地质灾害点等地质数据的基础。
一、GeoDataFrame的三层结构
一个GeoDataFrame可以拆成三个层次来看:索引(index)、属性列(columns)和几何列(geometry)。属性列与普通DataFrame完全一致,可以存字符串、数值、日期、类别;几何列则是一个GeoSeries,每个元素是Shapely几何对象(Point、LineString、Polygon等),并统一挂载一个坐标参考系(CRS)。
创建方式通常有两种。第一种是从带几何信息的字典直接构造:
import geopandas as gpd
from shapely.geometry import Point, LineString, Polygon
faults = gpd.GeoDataFrame(
{
"fault_id": ["F01", "F02"],
"fault_name": ["青龙断裂", "白水断裂"],
"fault_type": ["正断层", "逆断层"],
"length_km": [12.4, 8.7],
},
geometry=[
LineString([(102.1, 30.2), (102.5, 30.6)]),
LineString([(102.6, 30.1), (102.9, 30.4)]),
],
crs="EPSG:4326",
)
print(faults.crs)
print(faults.geom_type)
第二种是从Shapefile、GeoJSON、GPKG等文件读取:gpd.read_file("faults.shp")。读取后应立刻检查gdf.crs、gdf.geom_type.value_counts()和gdf.total_bounds,确认坐标系、几何类型和范围是否符合预期,这是地质数据入库前的第一道体检。
二、几何类型与地质要素的对应关系
地质矢量数据并非随意选择几何类型,而是由地质对象的空间形态决定。常见对应关系如下表(示例为教学假设数据):
| 几何类型 | 典型地质要素 | 关键属性示例 |
|---|---|---|
| Point / MultiPoint | 钻孔、泉点、滑坡监测点、采样点 | 孔深、水位、岩性代号 |
| LineString / MultiLineString | 断层、褶皱轴线、地质剖面线、河流 | 断层性质、走向、倾角 |
| Polygon / MultiPolygon | 地层单元、岩体、地质灾害易发区 | 地层代号、岩性、面积 |
需要特别注意:断层在中小比例尺下常被抽象为线,但在大比例尺构造建模中可能表示为带宽度和倾向的面;地层单元则几乎总是面。几何类型一旦确定,后续的空间查询、叠加分析和制图符号化都会依赖它,因此入库前应统一规范,避免同一图层混用点、线、面。
三、属性表操作:筛选、派生与连接
属性表操作是批处理中最频繁的环节。以断层图层为例,常见操作包括按属性筛选、派生新字段、按空间位置连接属性。下面示例均为教学假设数据:
# 1) 按属性筛选:只保留正断层且长度大于10km
sel = faults[(faults["fault_type"] == "正断层") & (faults["length_km"] > 10)]
# 2) 派生字段:按长度分级
faults["length_class"] = faults["length_km"].apply(
lambda v: "长" if v >= 10 else ("中" if v >= 5 else "短")
)
# 3) 空间连接:把断层与地层面叠加,取断层穿过的地层代号
strata = gpd.read_file("strata.gpkg")
joined = gpd.sjoin(faults, strata[["stratum_code", "geometry"]],
how="left", predicate="intersects")
print(joined[["fault_id", "stratum_code"]])
这里的关键判断点有三个:筛选条件必须用&、|并加括号,避免运算符优先级错误;派生字段用apply或map时要注意空值和类型;sjoin的predicate参数决定空间关系(intersects、within、contains),选错会直接导致属性挂接错误。执行后应检查行数变化和stratum_code的空值比例,判断连接是否合理。
四、空间参考初识:CRS不是可选项
坐标参考系(CRS)定义了几何坐标如何对应地球表面。地质数据常见两类:地理坐标系(如EPSG:4326,单位度)和投影坐标系(如EPSG:4547,CGCS2000 3度带,单位米)。长度、面积、缓冲区等计算必须在投影坐标系下进行,否则以度为单位的“长度”没有地质意义。
# 查看与转换 CRS
print(faults.crs) # EPSG:4326
faults_m = faults.to_crs("EPSG:4547") # 转为米制投影
faults_m["length_m"] = faults_m.length
print(faults_m[["fault_id", "length_m"]].head())
实操中要养成三个习惯:读入后先查crs是否为None;跨图层叠加前确认两者CRS一致,不一致先用to_crs统一;需要距离或面积时先投影再计算。若crs为None,说明数据缺少空间参考信息,应结合数据来源补设,而不是直接假设为WGS84。
crs、geom_type.value_counts()、total_bounds和空几何数量,能提前发现大多数入库问题。把GeoDataFrame的结构、几何类型与地质要素的对应、属性表操作和CRS这四件事串起来,就形成了地质矢量数据批处理的基本数据模型:属性描述“是什么”,几何描述“在哪里、什么形态”,CRS保证“位置和量算可信”。后续的批量裁剪、叠加、制图与入库,都建立在这一模型之上。