水质预测模型精度评估实例

news2024/11/18 1:42:09

研究背景

随着水资源管理需求的日益增长,水质预测模型的精准度成为了评估其有效性的关键因素。本文旨在通过实证研究,探讨自建水质预测模型的实际应用效能,通过与真实监测数据的比对,揭示模型预测精度的真实情况。

数据基础情况

数据来源:自研水质模型预测结果
时间范围:2023 年全年
指标:高锰酸盐指数、总磷、氨氮、氟化物

模型简介

本研究采用基于一维水质的机理模型,通过实时监测数据动态调整降解系数与污染物迁移速度,实现了单次对高锰酸盐指数、总磷、氨氮、氟化物长达20天以上的高适应性预测,尤其擅长捕捉水质突变事件。

当前预测界面

曲线图展示当前最新的预测结果。下部展示预测结果是否超标,峰值及超标时间范围,预测月均值与实际累计月均值。
Fig.1 模型可视化页面

模型评价界面

可以查询历史预测区间的预测结果对比。下部为模型评价,通过多元统计指标(如MAPE、RMSE)深入剖析模型性能,特别是通过准确率区间分布图,多维度验证了模型的稳定性和可靠性。

Fig.2 模型评价界面

模型精度评价方法

为了评估模型的准确率,本文采用比较直观的“预测误差率”来表达,用于评估预测值与真实值之间的接近程度。
A = 1 − ∣ Y − Y ^ ∣ Y \text{A} = 1 - \frac{|Y - \hat{Y}|}{Y} A=1YYY^
A 表示相对准确性,𝑌 是观测到的真实值(或准确值),而 Y^ 是模型预测的值。这个公式量化了预测误差相对于真实值的比例,其逆值给出了预测相对于实际观察值的接近程度,可以视为一种衡量预测准确性的度量,这种表达通常被称为相对误差的倒数或者归一化绝对误差。

理论情况下,模型每天至少运行一次,预测因子包括高锰酸盐指数、总磷、氨氮、氟化物,每次预测不少于 7 天,模型评价方法是每个因子,每次所有预测结果,依次与监测指标进行比对,单个指标每次每个值得预测准确率计为 A。
A ˉ = 1 N ∑ i = 1 N A i \bar{{A}} = \frac{1}{N} \sum_{i=1}^{N} A_i Aˉ=N1i=1NAi
这段公式表示求所有单次单个因子所有预测值的算术平均,其中 N 是预测值的数量。
用这种方法观察一年每次预测准确率的变化。

Python 代码实现

创建了一个 WaterQualityPredictor 类,该类封装与数据库交互、数据处理、预测数据获取、监测数据获取、准确率计算以及绘图等操作。

import pandas as pd
import matplotlib.pyplot as plt
import pymysql
from datetime import datetime
from sklearn.metrics import mean_absolute_error
class WaterQualityPredictor:
    def __init__(self, db_config):
        self.db_config = db_config
        self.conn = self._connect_db() 
    def _connect_db(self):
        """连接数据库"""
        conn = pymysql.connect(**self.db_config)
        return conn
    def fetch_model_data(self, sql):
        """从数据库获取模型数据"""
        df = pd.read_sql(sql, self.conn)
        return self._process_data(df) 
    @staticmethod
    def _process_data(df):
        """处理数据,包括时间格式转换和数值处理"""
        df["create_time"] = pd.to_datetime(df["create_time"])
        df["start_time"] = pd.to_datetime(df["start_time"])
        df["date_time"] = pd.to_datetime(df["date_time"])
        for col in ["CODmn", "NH3", "TP", "F"]:
            df[col] = df[col].astype(float).round(3)
        return df
    def get_prediction_dataset(self, factor, create_time, prediction_days=7):
        """根据因子和创建时间获取预测数据集"""
        subset = self.model_data[(self.model_data["create_time"] == create_time) & (self.model_data[factor].notnull())].iloc[:6*prediction_days]
        subset = subset[["date_time", factor]].set_index("date_time").reset_index()
        return subset
    def fetch_monitor_data(self, begin_time, end_time, station, period):
        """获取监测数据"""
        # 这里省略具体的请求逻辑,
        pass 
    def calculate_accuracy(self, prediction_df, monitor_df, factor):
        """计算准确率"""
        concatenated_data = pd.merge(prediction_df, monitor_df, on="date_time", suffixes=('', '_y'))
        concatenated_data['Accuracy'] = 1 - (abs(concatenated_data[factor] - concatenated_data[factor+'_y']) / concatenated_data[factor])
        concatenated_data['Accuracy'] = concatenated_data['Accuracy'] * 100
        average_accuracy = concatenated_data['Accuracy'].mean()
        return round(average_accuracy, 4)
    def plot_comparison(self, concatenated_data, factor):
        """绘制预测值与监测值对比图"""
        if concatenated_data['date_time'].equals(concatenated_data['date_time_y']):
            plt.figure(figsize=(10, 6))
            plt.plot(concatenated_data['date_time'], concatenated_data[factor], label='Prediction', marker='o')
            plt.plot(concatenated_data['date_time_y'], concatenated_data[factor+'_y'], label='Monitor', marker='x')
            plt.xlabel('Date Time')
            plt.ylabel(factor + ' Value')
            plt.title(f'Comparison of {factor} Prediction and Monitor Values')
            plt.xticks(rotation=45)
            plt.legend()
            plt.show()
        else:
            print("date_time and date_time_y are not aligned")
    def run_analysis(self, factor, create_time, station, period, prediction_days=7):
        """执行整个分析流程"""
        self.model_data = self.fetch_model_data("SELECT * FROM mechanism")
        prediction_df = self.get_prediction_dataset(factor, create_time, prediction_days)
        monitor_df = self.fetch_monitor_data(prediction_df["date_time"].min(), prediction_df["date_time"].max(), station, period)
        accuracy = self.calculate_accuracy(prediction_df, monitor_df, factor)
        print(f"Average Accuracy: {accuracy}%")
        self.plot_comparison(pd.concat([prediction_df, monitor_df], axis=1), factor) 

if __name__ == "__main__":
    db_config = {
        "host": "",
        "port": ,
        "user": "",
        "password": "",
        "db": "",
        "charset": ""
    }
    predictor = WaterQualityPredictor(db_config)
    predictor.run_analysis("factor", datetime.now() - timedelta(days=7), "station", "h4")

实现任意预测时间的单词预测结果对比。
Fig.3单次预测高指预测对比

折线图分析准确率变化

循环计算单词预测结果,取 2023 年整个时间段,四个指标准确率变化分别绘图。
Fig.4 预测精度折线图
注:部分预测异常时段,存在站点运行问题,为展示真实预测情况,未对齐进行剔除。从预测异常的频次看出,异常频率并不高。

饼图分析准确率占比

为了更直观的分析预测准确率的分布,对四个因子准确率的分布划分为(小于40, 40~60, 60~80, 80~100)四个区间,分别作图如下。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np 
def prepare_data_for_piechart(df, column):
    bins = [-np.inf, 40, 60, 80, 100]
    labels = ['<40%', '40%-60%', '60%-80%', '80%-100%']
    # 使用cut函数将数据切分为区间,并计算每个区间内数据点的数量
    intervals = pd.cut(df[column], bins=bins, labels=labels, include_lowest=True)
    # 计算每个区间的频率
    frequencies = intervals.value_counts(normalize=True) * 100
    return frequencies
columns_to_analyze = df_2023.columns.tolist() 
fig, axs = plt.subplots(2, 2, figsize=(12, 8), facecolor='white')
axs = axs.ravel()  # 将2x2的数组展平以便循环 
for i, column in enumerate(columns_to_analyze):
    if i < len(axs):  # 确保不会超出子图的范围
        frequencies = prepare_data_for_piechart(df_2023, column)
        axs[i].pie(frequencies, labels=frequencies.index, autopct='%1.1f%%')
        axs[i].set_title(f'{column} Precision Distribution')
        axs[i].axis('equal')  # 确保饼图是圆形
# 隐藏未使用的子图
for j in range(i+1, len(axs)):
    fig.delaxes(axs[j])
plt.tight_layout()
plt.show()

Fig.5 预测准确率分布饼图

上图表明,高锰酸盐指数准确率超过 60%的比例占比 95.4%,总磷准确率准确率超过 60%的比例 91.7%。详细指标可见下表。

年平均准确率预测天数>80%80~ 60%
高锰酸盐指数84.7832783.214.1
总磷79.5232770.621.1
氨氮-1863210.94
氟化物81.2711936.163.95
注:受站点运行情况影响,部分时段无数据。

直方图分析准确率分布

直方图(Histogram)是一个更好的可视化选择,因为它能清晰地展示每个准确率区间内的数据点数量,非常适合观察数据分布特征,如中心趋势、偏斜程度及异常值等。

import matplotlib.pyplot as plt
bin_width = 10
bins = list(range(0, 110, bin_width)) + [100]  # 包含100%的边界
# 创建一个2x2的子图网格
fig, axs = plt.subplots(2, 2, figsize=(12, 10))
# 遍历每个因子,并绘制其准确率的直方图
for i, column in enumerate(df_2023.columns):
    row = i // 2
    col = i % 2
    # 绘制直方图
    axs[row, col].hist(df_2023[column], bins=bins, edgecolor='black', alpha=0.7)
    axs[row, col].set_title(f'{column} Accuracy Distribution')
    axs[row, col].set_xlabel('Accuracy (%)')
    axs[row, col].set_ylabel('Frequency')
# 如果因子少于4个,隐藏多余的子图
for ax in axs.flat[len(df_2023.columns):]:
    ax.axis('off')
# 紧凑布局
plt.tight_layout()
plt.show()

Fig.6 预测精度分布直方图
直方图能清晰的看出高锰酸盐指数、总磷预测准确率更好,且分布更集中。

本模型氨氮预测准确率低的原因是:该目标站点氨氮指标长期较低。月均值波动在 0~0.2 之间,小时值可能长期处于 0~0.1 之间,即使较小的波动,准确率的值波动也很大。同时氨氮指标该站点与上游站点的关系不密切,只有较大的污染传递才能引起轻微升高。
经过长期观察,氨氮并非该站点的重点污染指标。

结论

  1. 机理模型在某站点高锰酸盐指数、总磷、氟化物等指标 2023 年的预测均有较好的表现。以准确率(归一化绝对误差的逆)评价,累计分别为 84.78%、79.52%、81.27%。
  2. 由于氨氮值较低,且与上游站点变化较弱,对于氨氮指标的预测准确率不高。也因为氨氮值较低并非重点关注对象,若要考虑提高预测精度,可选择大数据模型,如 LSTM、prophet 等。
  3. 准确率(归一化绝对误差的逆)并不是水质模型精度评价的必选指标,只是因为其较为通俗易懂,而受用户认可,仍需注意其具有一定的局限性,作为一个模型评价的参考指标即可,不宜过分求高,水质模型是否准确,应考虑其预测水质变化的能力,水质影响(峰值、污染持续时间)等,是否能够知道业务需要,才是水质模型最重要的指标。

综上所述,本研究构建的机理模型在多数水质指标预测上展现了良好的效果,尤其在高锰酸盐指数、总磷和氟化物的预测上取得了显著成绩。然而,氨氮预测的挑战凸显了模型对低浓度污染物处理能力的局限,后续将结合先进的机器学习技术以增强特定条件下的预测能力。水质模型的终极目标不仅是追求高精度数值,更重要的是能否有效指导水环境管理和应对策略,确保模型服务于实际的环境治理需求。

以上就是实际机理模型的应用精度分析,如果对你有启发,请点赞关注,如果有不对的地方请帮忙指正,水质预测是很小众的领域,希望得到同行的支持和指导。

微信公众号:环境猫er

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1712233.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【任务调度】Apache DolphinScheduler中关于全局参数设置、自定义参数、补数的介绍

Apache DolphinScheduler是一个分布式和可扩展的开源工作流协调平台&#xff0c;具有强大的DAG可视化界面。 今天在海豚调度的一个接口中想入参一个当前时间(要求格式为yyyyMMddhhmmss),找了找发现如下几种方法,给记录一下&#xff1a; 1.全局参数设置 在设置DAG图名称这一位…

CTF实战分享 | RWZIP

前言 首先我们要了解&#xff0c;压缩包本身并不具备隐藏信息的功能&#xff0c;但由于在CTF竞赛中&#xff0c;经常出现压缩包与隐写术结合在一起的题目&#xff0c;所以我们需要掌握在CTF竞赛中有关 ZIP 压缩包题目的常见题型及分析手段。 读者福利 | CSDN大礼包&#xff1a…

css设置文字在固定宽度中等距分开(仅限于单行文本)

一、要实现的效果&#xff1a; 二、代码 要在CSS中设置文本在一个固定宽度的容器中等距分开&#xff0c; 可以使用text-align: justify;属性&#xff0c;它可以让文本两端对齐&#xff0c;看起来就像是等距分开的。 但是要注意&#xff0c;单独使用text-align:justify;只能对单…

Midjourney如何控制光照?提示词灵感来了!

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Midjourney如何控制光照&#xff1f;提示词灵感来了&#xff01;文章目录 前言总结 前言 Midjourney v6 已经更新好久了&#xff0c;你知道有哪些可以控制光照效果的关键词吗…

数据结构---单向链表

思路分析&#xff1a; 1. 设计 struct LinkNode 节点结构体 strut LList 链表结构体 typedef void *LinkList 给用户使用链表指针 2. 初始化链表 LinkList mylist init_LinkList(); 3. 插入链表 void inser…

使用python实现炫酷的渐变色

使用python实现炫酷的渐变色 1、前言2、所需条件3、实现步骤步骤1&#xff1a;定义渐变函数步骤2&#xff1a;将渐变应用于目标颜色步骤3&#xff1a;定义参数并执行 4、完整代码5、总结 1、前言 通过应用颜色渐变&#xff0c;可以大大提升图像的视觉效果。在这篇博客中&#…

2025第十届美陈展

展位又遭疯抢&#xff01;2025第十届美陈展释放“无界之美” 美是全球通用的语言&#xff0c;人类对美的追求始终如一&#xff0c;大众审美在经历了时代的变迁后开始趋同&#xff0c;东方文明深处的美学经济开始崛起。 在如今商业迈入存量阶段&#xff0c;以品牌为突破口打造…

基于VMware安装Linux虚拟机

1.准备Linux环境 首先&#xff0c;我们要准备一个Linux的系统&#xff0c;成本最低的方式就是在本地安装一台虚拟机。为了统一学习环境&#xff0c;不管是使用MacOS还是Windows系统的同学&#xff0c;都建议安装一台虚拟机。 windows采用VMware&#xff0c;Mac则采用Fusion …

有免费通配符证书吗?哪里可以申请?

市面上的免费SSL证书大多数为单域名证书&#xff0c;如果您的主域名拥有众多子域名&#xff0c;逐一申请单域名SSL证书不太现实&#xff0c;下面为介绍一款永久免费使用的通配符SSL证书申请流程 1 选择免费通配符证书提供商 免费通配符证书申请点击这里直接获取https://www.…

【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化+完美使用

模版介绍 【DZ模板】价值288克米设计APP手机版DZ模板 数据本地化完美使用 腾讯官方出品discuz论坛DIY的后台设置&#xff0c;功能齐全&#xff0c;论坛功能不亚于葫芦侠&#xff0c;自定义马甲&#xff0c;自定义认证&#xff0c;自定义广告&#xff0c;完全可以打造出自己想…

据阿谱尔APO Research调研显示,2023年全球模塑纤维包装市场销售额约为60.4亿美元

根据阿谱尔 (APO Research&#xff09;的统计及预测&#xff0c;2023年全球模塑纤维包装市场销售额约为60.4亿美元&#xff0c;预计在2024-2030年预测期内将以超过2.7%的CAGR&#xff08;年复合增长率&#xff09;增长。 对永续和环保包装解决方案的需求不断增长&#xff0c;以…

Python | Leetcode Python题解之第103题二叉树的锯齿形层序遍历

题目&#xff1a; 题解&#xff1a; class Solution:def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:if not root: return []res, deque [], collections.deque()deque.append(root)while deque:tmp []# 打印奇数层for _ in range(len(deque)…

java8以上版本

java9及其以上版本 一、JDK17 LTS 常用新特性1、switch语句的增强2、字符串拼接3、判断类型instanceof自动类型转换4、密封类 关键字 sealed permits5、record类6、优化空指针异常7、ZGC垃圾收集器 一、JDK17 LTS 常用新特性 1、switch语句的增强 在 Java 17中&#xff0c;sw…

全面指南:IP SSL证书的申请与部署步骤

不同于常见的域名型SSL证书&#xff0c;IP SSL证书是专门用于为IP地址提供安全保护的SSL证书类型&#xff0c;适用于那些直接通过IP地址访问的网站或服务。本文将详细介绍IP SSL证书的申请步骤及其部署过程&#xff0c;帮助您轻松实现IP地址的安全加密。 一、了解IP SSL证书 …

CSS Canvas鼠标点击特效之天女散花(文本粒子动画)

1.效果 2.代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><style>body,html {margin: 0;padding: 0;w…

Docker HTTPS api V2 Manifest V 2, Schema 2 下的免装docker下载镜像的方法

目录 前言 下载镜像代码 使用方法 原代码中无法适配 Schema 2 的原因浅析 如何解决 相对原代码改动的东西 前言 本文提供代码主要是基于 https://github.com/NotGlop/docker-drag 提供的代码修改的。链接中提供的代码应该是是基于HTTPS api V2 Manifest V 2, Schema 1实…

【算法实战】每日一题:统计一个序列向某个方向的比他小的数的个数(非暴力)

题目 统计一个序列向某个方向的比他小的数的个数 思路 用单调栈&#xff0c;虽然这里说的是统计比他小的&#xff0c;但是是求和&#xff0c;所以我们可以用在用单调栈的时候统计里面所有比他大的元素 这两个级别上是一样的 伪代码 声明变量 n、num 和 sum 为整数。 声明…

实操专区-第15周-课堂练习专区-漏斗图与金字塔图

实操专区-第15周-课堂练习专区-漏斗图 下载安装ECharts&#xff0c;完成如下样式图形。 代码和截图上传 基本要求&#xff1a;下图3选1&#xff0c;完成代码和截图 完成 3.1.3.16 漏斗图中的任务点 基本要求&#xff1a;2个选一个完成&#xff0c;多做1个加2分。 请用班级学号姓…

vue组件的基本使用方法

组件 【1】组件是什么&#xff1f; 组件就是&#xff1a;扩展 HTML 元素&#xff0c;封装可重用的代码&#xff0c;目的是复用例如&#xff1a;有一个轮播图&#xff0c;可以在很多页面中使用&#xff0c;一个轮播有js&#xff0c;css&#xff0c;html组件把js&#xff0c;cs…

使用 Django 连接 MySQL 数据库

文章目录 步骤一&#xff1a;安装必要的库和驱动步骤二&#xff1a;配置数据库连接步骤三&#xff1a;执行数据库迁移步骤四&#xff1a;开始使用 MySQL 数据库创建一个模型迁移模型到数据库使用模型进行数据操作创建新记录&#xff1a;查询记录&#xff1a;更新记录&#xff1…