3. 海底管道检测数据读取与初步观察

在海底管道检测项目中,数据到手后的第一件事不是急着画图或建模,而是把数据“看清楚”。检测数据可能来自多波束测深系统、侧扫声呐、惯性测量单元(IMU)、阴极保护电位记录仪或人工巡检台账,常见交付格式包括 CSV、Excel 和 JSON。pandas 为这三类格式都提供了成熟的读取接口,但读取只是起点,真正决定后续分析质量的是对数据形状、列类型、缺失值和基本统计量的系统观察。

一、按格式选择读取方式

CSV 是最常见的检测数据格式,通常由采集软件导出,字段以逗号或制表符分隔。读取时要关注编码、分隔符和表头是否存在:

import pandas as pd

# 常规 CSV,指定编码防止中文列名乱码
df = pd.read_csv("pipeline_inspection.csv", encoding="utf-8")

# 制表符分隔、无表头的导出文件
df = pd.read_csv("inspection_export.txt", sep="\t", header=None,
                 names=["point_id", "chainage_m", "depth_m", "cp_mv"])

Excel 文件常见于人工整理的巡检记录,可能包含多个工作表。用 sheet_name 指定工作表,避免默认只读第一张表而漏掉数据:

xls = pd.ExcelFile("inspection_records.xlsx")
print(xls.sheet_names)          # 先看有哪些工作表
df = pd.read_excel(xls, sheet_name="管段A")

JSON 多用于传感器或平台接口导出,结构可能是记录列表,也可能是嵌套字典。对于“每行一个对象”的列表型 JSON,pd.read_json 或 json_normalize 都能胜任;若字段嵌套较深,建议先用 json_normalize 展平再观察:

import json
from pandas import json_normalize

with open("sensor_log.json", encoding="utf-8") as f:
    raw = json.load(f)

df = json_normalize(raw["records"])   # 展平嵌套字段
读取后先执行 df.head() 和 df.tail(),确认首尾行是否被表头、单位行或汇总行污染。检测数据中常见的“合计”“备注”行会直接破坏数值列的类型推断。

二、形状与列类型:判断数据是否“像样”

df.shape 返回(行数,列数),是判断数据规模的第一指标。例如一条 12 公里管段、测点间距 2 米,理论上应有约 6000 个测点;若读入后只有 300 行,就要怀疑分隔符错误或文件被截断。df.columns 用于核对字段名是否与采集规范一致,df.dtypes 则揭示每列被 pandas 推断成什么类型。

类型观察中最容易出问题的是数值列被读成 object。原因通常是列中混入了“—”“N/A”“超限”等文本,或小数点使用了逗号。此时可用 pd.to_numeric(..., errors="coerce") 强制转换,无法转换的值会变为 NaN,反而便于后续统计缺失。时间列同样要显式转换:pd.to_datetime(df["record_time"], errors="coerce"),否则排序和按时间段筛选都会出错。

三、缺失值与基本统计量:发现异常的第一道筛子

缺失值观察用 df.isna().sum() 按列统计,配合 df.isna().mean() 得到缺失比例。检测数据中,阴极保护电位缺失往往意味着该测点未通电或记录仪故障,而埋深缺失可能是声呐未覆盖。缺失不是简单删掉了事,要先判断是“随机漏记”还是“系统性缺失”。

基本统计量用 df.describe() 获取数值列的计数、均值、标准差、最小、四分位数和最大值。对检测数据而言,min 和 max 尤其值得盯:埋深出现负值、电位出现 +500 mV 以上的正偏移、里程出现重复的 0,都提示单位错误、坐标约定不一致或数据拼接问题。describe(include="all") 还能同时给出文本列的频次信息。

检测数据读取与初步观察链路 原始检测文件 CSV / Excel / JSON 测深·电位·埋深·里程 编码 / 分隔符 / 工作表 pandas 读取 read_csv / read_excel read_json / json_normalize 指定编码与表头 初步观察三要素 形状 shape 行数·列数 列类型 dtypes 数值/时间/文本 缺失与统计 isna / describe 比例·极值 观察结果 → 判断与处理 数值列变 object to_numeric(coerce) 缺失比例偏高 区分随机/系统性缺失 极值越界 查单位·坐标·拼接 可进入下一步的干净数据 类型正确 · 缺失可控 · 量纲一致 · 里程连续

四、一个可复用的观察流程

把上述动作串成固定流程,能显著减少漏检。以下示例针对一份假设的管段检测 CSV,字段包括测点编号、里程、埋深、阴极保护电位和记录时间,数据为教学构造,不代表实测结果:

df = pd.read_csv("pipeline_inspection.csv", encoding="utf-8")

print(df.shape)                       # (6000, 5)
print(df.dtypes)                      # 检查 depth_m、cp_mv 是否为 float
print(df.isna().sum())                # 各列缺失计数
print(df.isna().mean().round(3))      # 缺失比例
print(df.describe().T)                # 转置后按列查看统计量

# 类型修正
df["record_time"] = pd.to_datetime(df["record_time"], errors="coerce")
df["cp_mv"] = pd.to_numeric(df["cp_mv"], errors="coerce")

# 里程连续性检查
print(df["chainage_m"].diff().describe())

假设读入后 shape 为 (6000, 5),depth_m 的 min 为 -0.8,cp_mv 的 max 为 620,record_time 缺失 12 条。这些信号分别指向:埋深负值可能是高程基准与埋深定义混用;电位正偏移可能是单位从 V 误录为 mV 或参比电极接反;时间缺失则需回查记录仪时钟同步。此时不应直接删除,而应带着问题回到原始文件核对。

不要用 df.dropna() 一键清空缺失行。检测数据中缺失本身携带信息,先统计缺失分布、判断成因,再决定填补、剔除还是标记,否则可能把系统性故障点当成噪声丢掉。

五、观察结论要落到判断依据上

初步观察的产出不是一堆打印结果,而是几条可复核的结论:数据规模是否与管段长度、测点间距匹配;关键数值列类型是否正确;缺失集中在哪些列、比例多少;统计量是否存在越界或量纲异常。把这些结论记录在分析日志中,后续清洗和建模才有据可依。对海底管道检测而言,埋深、电位、里程三类字段的可靠性直接决定腐蚀与悬跨评估的可信度,因此读取阶段的每一次类型转换和缺失统计,都值得认真对待。