4. 化验数据整理与可视化入门
污水厂化验室每天产生的数据看似简单——一个COD值、一个SV30读数、一台在线仪表的pH——但真正进入运行决策之前,这些数据必须经过整理。原始记录本上的数字往往存在格式不统一、个别缺失、偶发异常等问题,直接拿来画图或算平均值,很容易得出错误结论。本节围绕数据表规范、缺失值与离群值处理、趋势图与控制图绘制,以及Excel和Python两种工具的基本操作展开,目标是让化验数据从“记录”变成“可判断的依据”。
一、数据表规范:先让数据“排好队”
规范的数据表是后续一切处理的前提。污水厂化验数据表应遵循“一行一条记录、一列一个变量”的原则,避免合并单元格、避免在数值中混入单位文字。推荐的最小字段包括:采样日期、采样时间、采样点位、检测项目、检测值、单位、检出限(必要时)、检测方法、检测人、备注。其中“检测项目”采用统一命名,例如统一写“CODCr”而不是“COD”“化学需氧量”混用;点位统一写“进水口”“曝气池末端”“二沉池出水”等固定名称。
一个常见的错误是把不同检测项目横向铺开成很多列,每列一个项目,看似紧凑,但当项目增减或方法变更时表格结构就会混乱。更稳妥的做法是“长表”结构:每条记录只对应一个项目一个值,需要横向对比时再用数据透视表转换。下表给出一个符合规范的示例片段(数值为教学示例,非实测):
| 采样日期 | 点位 | 检测项目 | 检测值 | 单位 | 检测方法 | 备注 |
|---|---|---|---|---|---|---|
| 2024-05-06 | 进水口 | CODCr | 286 | mg/L | 重铬酸钾法 | |
| 2024-05-06 | 进水口 | 氨氮 | 31.4 | mg/L | 纳氏试剂法 | |
| 2024-05-06 | 曝气池末端 | SV30 | 28 | % | 量筒沉降 | |
| 2024-05-06 | 二沉池出水 | CODCr | — | mg/L | 重铬酸钾法 | 水样不足 |
注意最后一行的“—”表示缺失,而不是填0。缺失与“检测结果为0”在含义上完全不同,填0会直接拉低均值并扭曲趋势,这是数据整理中最需要警惕的细节之一。
二、缺失值与离群值:区分“没测到”和“测错了”
缺失值分两类:一类是客观未采样或水样不足,另一类是记录遗漏。处理方式取决于后续用途。若只是绘制趋势图,可对短缺口采用线性插值或前值延续,但必须在图上标注;若用于计算月均值或达标率,则不宜随意填补,应明确“有效数据天数”,按实际有效样本计算。对于连续多日缺失,插值会制造虚假的平稳趋势,此时应保留缺口,让看图的人知道数据不完整。
离群值更需要谨慎。化验数据中的离群值可能来自三种原因:真实的工艺突变(如冲击负荷)、采样或保存失误、检测操作误差。判断时不能只看数值大小,要结合上下文。常用辅助方法包括:与同点位历史数据比较、与同日其他相关指标交叉验证(如COD异常升高时看SS、氨氮是否同步变化)、检查备注栏是否有异常记录。统计上可用“均值±3倍标准差”或箱线图的1.5倍四分位距作为初筛,但筛出的点必须回到原始记录核实,不能直接删除。
三、趋势图与控制图:让波动“说话”
趋势图用于观察指标随时间的变化方向,横轴为时间、纵轴为检测值,同一图上可叠加控制限或标准限值。绘制时注意时间轴等间距处理,缺失日期不要压缩,否则会误判变化速率。控制图则在趋势图基础上加入中心线(CL)、上控制限(UCL)和下控制限(LCL),用于区分“正常波动”与“异常信号”。
以曝气池末端SV30为例,取连续20天的教学示例数据,计算均值约为27%,标准差约3.2%,则UCL≈36.6%、LCL≈17.4%。当某日SV30升至38%并连续两天高于UCL,提示污泥沉降性能可能恶化,应结合镜检和食微比排查。控制图的判异不只看单点越限,连续7点位于中心线同侧、连续上升或下降等模式同样值得关注。下图展示了从原始记录到控制图判断的完整数据链路:
四、Excel与Python的基本操作
Excel适合日常快速整理。关键操作包括:用“数据验证”限制检测项目下拉选项,减少命名不一致;用IF与ISBLANK组合标记缺失;用AVERAGEIFS按点位和项目计算有效均值;用“插入-折线图”绘制趋势图后,手动添加控制限系列(把UCL作为一列常数画成直线)。条件格式可对超出UCL的单元格自动标红,便于快速巡检。
当数据量增大或需要重复处理时,Python更合适。用pandas读取Excel后,先统一列名与单位,再用to_numeric(errors='coerce')把“—”“未检出”等转为缺失,用isna()统计缺失比例。离群值初筛可用:
import pandas as pd
df = pd.read_excel("sv30.xlsx")
df["检测值"] = pd.to_numeric(df["检测值"], errors="coerce")
mean, std = df["检测值"].mean(), df["检测值"].std()
df["疑似离群"] = (df["检测值"] - mean).abs() > 3 * std
print(df[df["疑似离群"]]) # 输出后逐条回查原始记录
绘图可用matplotlib,把CL、UCL、LCL作为水平参考线叠加,缺失值自然断线。无论用哪种工具,核心原则一致:先规范结构,再处理缺失与异常,最后才画图判断。图表是结论的载体,而不是数据的装饰;每一处插值、修正和删除,都应当能在图上或备注中被追溯。