2. 钻孔CSV数据解析基础

把地质钻孔资料从Excel或台账转成Shapefile,第一步不是打开GIS软件,而是把CSV读“干净”。CSV看似简单,实际是整条数据链中最容易埋雷的环节:编码不对,孔号里的“ZK-1”可能变成乱码;分隔符选错,整行被挤进一个字段;坐标列混入单位或空格,后续投影校验必然失败。本节围绕四个问题展开:CSV格式规范、字段含义识别、编码问题处理、缺失值与异常值初检,目标是产出一份“可被程序稳定读取、字段语义明确、数值可信”的中间表。

一、CSV格式规范:先确认它真的是CSV

CSV(Comma-Separated Values)的正式约定来自RFC 4180,核心规则有四条:以逗号分隔字段;含逗号、双引号或换行的字段必须用双引号包裹;字段内的双引号用两个双引号转义;行尾用CRLF或LF。工程中最常见的“假CSV”有三类:一是从Excel另存时选了“Unicode文本”,实际是制表符分隔的TXT;二是岩性描述里含中文逗号“,”被误当分隔符;三是单元格内换行导致一条钻孔记录跨了多行。

判断方法很直接:用文本编辑器打开,看第一行是否以逗号分隔;用Python快速探测分隔符与列数:

import csv
with open('boreholes.csv', encoding='utf-8-sig', newline='') as f:
    sample = f.read(4096)
    dialect = csv.Sniffer().sniff(sample, delimiters=',;\t')
    print('分隔符:', repr(dialect.delimiter))
    f.seek(0)
    rows = list(csv.reader(f, dialect))
    print('列数分布:', {len(r) for r in rows})

若列数集合出现多个值(如{8, 9}),说明存在未转义的逗号或跨行字段,必须先修复再进入下一步。建议统一另存为“CSV UTF-8(逗号分隔)”,并在读取时显式指定 newline='',避免Windows下空行被解析成空记录。

二、字段含义识别:给每一列贴上语义标签

钻孔表通常包含孔号、X坐标、Y坐标、孔口标高、孔深、开孔日期、岩性、终孔直径等字段。难点不在字段多少,而在“同名异义”和“异名同义”:有的表用“孔号”,有的用“钻孔编号”“ZK_NO”;“孔深”可能指终孔深度,也可能指某一岩层的层底深度。识别时按三步走:先看表头文字,再看数据形态,最后对照原始台账或柱状图确认。

数据形态是重要线索:孔号多为“ZK”加数字;X/Y坐标通常是6~7位整数加3位小数(以米为单位的高斯投影坐标);孔深一般在几十到几百米之间;岩性为中文短语。若某列数值全部在0~500之间且带小数,更可能是标高或孔深,而非平面坐标。识别结果应固化为字段映射表,供后续脚本直接引用,避免每次手工对应。

原始列名标准字段类型示例识别依据
钻孔编号hole_id字符串ZK-01含字母前缀,唯一
X坐标coord_x浮点523841.2656位整数+3位小数
Y坐标coord_y浮点3287456.1187位整数+3位小数
孔口标高elevation浮点126.35数值小,带小数
孔深depth浮点85.600~500区间
岩性lithology字符串中风化砂岩中文短语

三、编码问题处理:乱码的定位与修复

中文CSV的编码常见三种:UTF-8(含或不含BOM)、GBK/GB18030、以及Excel导出的ANSI。用UTF-8读取GBK文件会报 UnicodeDecodeError,用GBK读UTF-8则出现“锟斤拷”或“”前缀。处理策略是先探测再统一:

raw = open('boreholes.csv','rb').read()
for enc in ('utf-8-sig','gb18030','utf-16'):
    try:
        text = raw.decode(enc)
        print('可用编码:', enc); break
    except UnicodeDecodeError:
        continue

确认编码后,统一转存为“UTF-8 with BOM”或纯UTF-8,并在读取时固定 encoding='utf-8-sig',可同时兼容带BOM与不带BOM的文件。若表头出现“孔号”,说明BOM未被剥离,用utf-8-sig即可消除。切勿用“替换非法字符”的方式强行读取,那会把真实孔号改坏且难以追溯。

四、缺失值与异常值初检

缺失值表现为空字符串、空格、“-”“/”“NULL”“无”等占位符,读取时应统一转为空值再统计。异常值检查聚焦四类:孔号重复或为空;坐标为空、为0、或数量级明显不符(如X只有5位);孔深≤0或超过合理上限;岩性为空。下面这段检查可直接输出问题清单:

import pandas as pd
df = pd.read_csv('boreholes.csv', encoding='utf-8-sig',
                 na_values=['',' ','-','/','NULL','无'])
print('孔号重复:', df['hole_id'].duplicated().sum())
print('坐标缺失:', df[['coord_x','coord_y']].isna().any(axis=1).sum())
print('孔深异常:', ((df['depth']<=0)|(df['depth']>500)).sum())
print('岩性缺失:', df['lithology'].isna().sum())

发现异常不要急于删除,先回查原始台账:坐标数量级不符往往是X/Y列颠倒或混入了经纬度;孔深为0可能是“设计孔深”未填。处理原则是“标记—核实—修正或剔除”,并在中间表中保留一列 qc_flag 记录处理状态,保证后续投影校验时能追溯每一条记录的来龙去脉。

钻孔CSV解析与初检流程 原始CSV Excel/台账导出 格式与编码探测 分隔符 / 列数 / 编码 utf-8-sig · gb18030 字段语义映射 孔号/坐标/孔深/岩性 统一为标准字段名 缺失值与异常值初检 重复孔号 / 坐标缺失 孔深越界 / 岩性为空 初检判定规则(示例阈值) 孔号为空或重复 → 标记 坐标缺失/为0 → 标记 孔深≤0或>500 → 复核 岩性为空 → 回查台账 处理原则:标记 → 核实 → 修正或剔除,保留 qc_flag 追溯列 通过初检的中间表 hole_id · coord_x · coord_y elevation · depth · lithology qc_flag(pass / fixed / drop) 进入下一环节 坐标列已确认、单位统一为米 孔号唯一、孔深可信 可生成点要素并做投影校验

完成上述四步后,应得到一份字段名统一、编码一致、异常已标记的中间表。它既是Shapefile点要素的直接数据源,也是后续投影校验的输入基准——如果这一层的坐标列含义或单位仍有歧义,后面无论怎么设置投影参数都无法得到可信结果。建议把字段映射表、编码探测结果和初检统计(总记录数、标记数、剔除数)一并记录在数据说明中,形成可复现的解析日志。