论文阅读:基于机器学习的生态组合塘强化城市污水处理厂脱氮优化
摘要
背景与痛点:在中国小城镇采用生态组合塘(ECPs)工艺的城镇污水处理厂,正面临进水水质波动下难以动态调整运行参数的困境。为满足严格的总氮(TN)排放标准,常出现曝气过量、外加碳源投加过度的问题。
研究目的与方法:为解决这些难题,亟需为采用生态组合塘的污水处理厂建立适宜的总氮强化去除模型。本研究采集了某采用生态组合塘工艺的全尺度城镇污水处理厂三年的运行数据,通过可解释性机器学习方法对出水总氮浓度进行预测与优化。其中,XGBoost 模型在训练集和测试集的决定系数(R²)分别达到 0.997 和 0.911,均方根误差(RMSE)分别为 0.196 和 1.283。借助 SHAP 分析与部分依赖图,本研究确定了优化的运行参数:在提升总氮去除效果的同时,实现了能耗与化学需氧量(COD)碳源投加量的平衡削减。
结论:研究还开发了图形用户界面,以支持工艺运行参数的持续预测与协同优化,最终达成了出水总氮、能耗及外加碳源用量的同步降低——其中出水总氮浓度下降 17.50%,年 COD 碳源投加量减少 33.29%。值得注意的是,采用生态组合塘工艺的污水处理厂展现出显著的碳减排潜力:仅通过强化总氮去除、降低能耗与碳源投加量,即可实现年碳减排量 788.40 吨二氧化碳。
材料与方法
生态组合塘运行概况
该大型城市污水处理厂位于中国浙江,采用生态组合塘(ECPs)工艺,设计处理能力为 60,000 m³/d。整个生态组合塘系统分为 13 个区域,各区平均水深为 8.8 m,具体构造包括:第一好氧区(1–5 区)、缺氧区(6–8 区)、第二好氧区(9–12 区)以及沉淀区(13 区)。运行过程中,在第一缺氧区(6 区)和第二缺氧区(7 区)添加了一种聚合物外加碳源,并将混合液从沉淀区回流至第一缺氧区(6 区)。

图 1。(a)全规模城市污水处理厂生态组合池的简化流程图;(b)通过 SHAP 分析和 PDP 确定了用于预测和优化废弃物 TN 浓度的机器学习框架,以及最优参数组合,以增强氮的去除效果,同时平衡能耗和 COD 剂量减少。
数据集信息
本研究收集了一座采用生态组合塘(ECPs)工艺的大型城市污水处理厂的日常运行数据,数据集包含自 2021 年 1 月 1 日至 2023 年 12 月 31 日期间共 1095 组时间序列数据。该厂系统监测了包括废水温度、进水 pH 值及出水化学需氧量(COD)浓度在内的 16 项关键运行参数,并通过严格的特征选择方案,确定了 13 个作为后续预测模型驱动因素的重要参数,具体包括:进水流量、进水氨氮、进水总氮、5 号区溶解氧、5 号区总氮、6 号区化学需氧量、6 号区总氮、7 号区溶解氧、7 号区化学需氧量、7 号区总氮、外加碳源、能耗以及出水总氮。
此外,研究采用 KNN 算法对采集的数据集进行了缺失值处理与离群值清洗,剔除了占总数据集不足 1% 的包含离群值的记录。
| 参数分类 | 参数名称 (中) | 英文缩写 | 备注 / 功能说明 |
|---|---|---|---|
| 进水特征 | 进水流量 | Flowrate_inf | 反映污水处理厂的实时水力负荷 |
| 进水氨氮 | NH_4^+-N_inf | 硝化过程的主要底物来源 | |
| 进水总氮 | TN_inf | 脱氮处理的总负荷基础 | |
| 过程监控 | 5 区溶解氧 | DO_5 | 第一好氧区末端的充氧状态 |
| 5 区总氮 | TN_5 | 第一好氧区后的氮素残留情况 | |
| 6 区化学需氧量 | COD_6 | 第一缺氧区的碳源水平 | |
| 6 区总氮 | TN_6 | 第一缺氧区的脱氮初步效果 | |
| 7 区溶解氧 | DO_7 | 第二缺氧区的环境状态 (需维持低 DO) | |
| 7 区化学需氧量 | COD_7 | 第二缺氧区用于反硝化的有效碳源 | |
| 7 区总氮 | TN_7 | 深度脱氮后的氮素水平 | |
| 操作/控制 | 外部碳源投加量 | ECS | 人为干预以增强反硝化的关键手段 |
| 能耗 | EC | 反映曝气和回流等操作的运行成本 | |
| 预测目标 | 出水总氮 | TN_eff | 核心预测变量,衡量排放是否达标 |
模型开发与评估
在模型开发阶段,预处理后的数据集按 8:2 的比例划分为训练集(80%)和测试集(20%)。为提升模型的泛化能力,研究首先通过 Pearson 相关性分析剔除预测增益低且存在共线性的特征;同时,引入 SHAP(SHapley Additive exPlanations)值系统评估包括出水总氮在内的 16 个初始特征的重要性,剔除冗余项。基于对特征显著性、相关性及模型复杂度的综合平衡,最终构建了包含出水总氮在内的 13 个关键特征的精简数据集。
模型开发在 Anaconda 平台的 JupyterLab 环境中基于 Python 3.8 完成,并采用提前停止(Early Stopping)策略防止过拟合——若验证集均方误差连续 50 轮未改善则停止训练。通过网格搜索(Grid Search)进行超参数优化,并结合 5 折交叉验证评估模型性能以降低结果方差。评价指标选用决定系数和均方根误差。研究对比了多元线性回归(MLR)、支持向量机(SVM)、轻量级梯度提升机(LightGBM)、随机森林(RF)、极端梯度提升(XGBoost)和类别特征提升(CatBoost)六种机器学习算法,旨在筛选出处理总氮去除任务的最佳模型。
总氮(TN)去除的优化策略
基于预测模型的输出结果,本研究通过调整工艺参数制定了针对性的脱氮优化策略。研究采用 SHAP 方法和部分依赖图(PDP)来评估最优模型中各特征的相对重要性。SHAP 是一种基于博弈论的机器学习解释方法,通过计算每个特征对模型输出的贡献度(即 SHAP 值),不仅能量化单个变量及其相互作用对预测值的正负影响,还能揭示这些影响在不同观测值间的变化规律。
为进一步衡量特征对模型整体预测的重要性,研究计算了平均绝对 Shapley(MAS)值。通过 SHAP 摘要图可以清晰阐明影响总氮去除的因素排序,而 PDP 则用于深入理解各特征的影响力及其相关性,并利用二维部分依赖图(2D-PDP)分析两个特征间的交互作用对预测结果的影响。
在研究实施中,利用 Python 的 shap 和 pdpbox 库进行数据分析与绘图,并将每个数据集对应的最优模型指定为解释器(Explainer)。研究流程在利用 PDP 分析出同时降低出水总氮与能耗的最优参数范围后,构建了用于出水总氮预测与优化的机器学习框架。通过 SHAP 分析确定的最优参数组合,旨在平衡脱氮效率、能耗及 COD 投加量。为便于实际应用,研究基于 tkinter 库开发了用户友好的图形用户界面(GUI)。此外,采用简化的带策略非支配排序遗传算法(NSGA-II)解决出水总氮、能耗与外加碳源消耗之间的多目标优化问题,并结合逼近理想解排序法(TOPSIS)获取最佳运行参数组合。
结果与讨论
基于出水总氮(TN)浓度的模型评估与比较
结果显示,MLR 的预测能力有限(测试集 R² = 0.459),而其余五种非线性模型的性能表现优异,测试集 R²均在 0.775 至 0.829 之间。其中,XGBoost 模型表现最为突出,训练集准确率接近完美(R² = 0.999,RMSE = 0.073),但在测试集上的泛化能力略弱(R² = 0.829)。
随后,研究通过 SHAP 分析对特征贡献度进行了量化。结果发现,进水 pH 值和进水氨氮(NH_4^+-N)的特征重要性最低(0.020),对模型性能提升的贡献微乎其微。考虑到进水 pH 值长期稳定在 6.5–7.5 之间,将其判定为冗余特征并予以剔除;而进水氨氮因与出水总氮存在潜在关联,故予以保留。
通过 Pearson 相关系数分析各特征与出水总氮的相关性发现,出水 COD 和废水温度与出水总氮的相关性较弱,且与其他特征之间也无显著强相关性。因此,为了降低模型复杂度并增强泛化能力,研究最终剔除了废水温度、进水 pH 和出水 COD 这三个冗余特征。
经过特征修剪后,对各模型进行了重新训练。优化后的 XGBoost 模型性能显著提升,训练集和测试集的 R²分别达到 0.997 和 0.911,RMSE 分别为 0.196 和 1.283。结果表明,由 SHAP 特征重要性评估引导的降维策略极大地改善了模型表现,最优模型(XGBoost)的测试集 R²从 0.829 提高到了 0.911。

图 2. 以出水总氮浓度为目标特征的六种机器学习模型训练图:(a) 多元线性回归 (MLR);(b) 支持向量机 (SVM);(c) 随机森林 (RF);(d) 轻量级梯度提升机 (LightGBM);(e) 类别特征提升 (CatBoost);(f) 极端梯度提升 (XGBoost)。图中红线表示测试集的回归拟合线,粉色区域则代表这些回归线周围的 95% 置信区间。
基于 SHAP 和 PDP 的模型灵敏度分析
研究采用 SHAP 和 PDP(部分依赖图)方法分析特征重要性,阐明 XGBoost 模型的预测机制,并识别影响出水总氮浓度的关键参数。结果显示,TN_7、EC(能耗)、DO_5、TN_6、进水流量以及 DO_7 是决定出水总氮浓度的最重要特征。其中,TN_7 和 TN_6 为水质指标,而 EC、DO_5 和 DO_7 则是具有可控潜力的工艺参数。值得注意的是,DO_5 和 DO_7 与能耗(EC)显著相关,这为后续制定智能节能策略提供了逻辑基础。
为了进一步探究特征对模型输出的具体影响,研究利用 PDP 考察了单特征及多特征交互作用对出水总氮的影响。出水总氮受硝化和反硝化过程的共同调节。DO_5 的部分依赖图显示,维持较高的 DO_5 浓度有利于提高总氮去除效率;5 号区作为好氧区,较低的溶解氧会抑制微生物的硝化作用。然而,由于该工艺中 5 号区的曝气兼具搅拌功能,导致其 DO_5 浓度时常超过 10 mg/L,这凸显了利用机器学习优化 DO_5 以降低能耗的必要性。
DO_7 与出水总氮浓度呈正相关。这是因为 7 号区为缺氧区,较高的溶解氧会干扰反硝化效率。同时,COD_6 和 COD_7 的 PDP 结果表明,适量的 COD 投加能增强脱氮性能,但过量投加则会增加废水负荷与化学品消耗,反而对反硝化产生不利影响。
在多特征交互分析方面,表明较低的 DO_7 与较高的 DO_5 结合可实现更高的脱氮效率。外加碳源(ECS)与 COD_6、COD_7 之间的转换关系,结果暗示较低浓度的 ECS 和 COD 组合有助于降低出水总氮。综上所述,强化脱氮效率的最优运行区间为:DO_5控制在 5.8–8.8 mg/L,DO_7 在 0.3–2.8 mg/L,COD_6 在 28.0–35.5 mg/L,COD_7 在 0–26.4 mg/L,且 ECS 投加量控制在 1.9–2.3 m³/d。
识别并排序影响脱氮性能的关键参数
污水处理厂的生态组合塘(ECPs)旨在通过好氧硝化和缺氧反硝化实现脱氮。如图 3 所示,TN_7、EC(能耗)和 DO_5 是影响脱氮效率的三大核心参数。由于 5 号区作为最后的好氧区且溶解氧(DO)未受控制,导致后续的 6 号区(第一缺氧区)DO 浓度升高,即便添加外加碳源也难以发生反硝化作用;同理,8 号区(第三缺氧区)因缺乏碳源也无法进行反硝化,而 9-12 号好氧区主要负责将残余氨氮转化为硝态氮,对总氮去除的贡献极小。相比之下,7 号区(第二缺氧区)通过控制 DO 浓度并添加外加碳源,促进了显著的反硝化过程,因此 TN_7成为影响出水总氮浓度最关键的参数。
此外,5 号区和 7 号区不受控的 DO 浓度导致了过度曝气,从而增加了电力消耗;同时,在进水水质波动的情况下,外加碳源的不规范投加也造成了化学品的过量使用,这两者共同推高了整体能耗,使 EC 成为影响脱氮效率的第二大关键参数。值得注意的是,5 号区的最高 DO 浓度超过了 9.0 mg/L,这种缺乏控制的过度曝气使得本应作为第一缺氧区的 6 号区呈现出好氧特性,这也解释了为何 DO_5 会成为影响脱氮性能的第三大重要参数。
强化脱氮与平衡能耗及 COD 投药量的参数优化
机器学习模型的研究结果强调了优化工艺参数以同步降低出水总氮(TN_eff)浓度、能耗(EC)和 COD 投药量的重要性。为了便于实际工程应用,本研究开发了一个集成 TN_eff、EC 和 COD 投药量模型的图形用户界面(GUI)。
该 GUI 基于 PDP 分析推导出的最优控制参数区间,并集成了简化版的 NSGA-II(带策略非支配排序遗传算法)和 TOPSIS(逼近理想解排序法)算法。通过该优化控制策略,用户可以灵活调整关键运行参数;在输入进水水质数据(如进水氨氮、进水总氮、5/6/7 号区总氮浓度)及核心工艺参数(如进水流量、5/7 号区溶解氧、6/7 号区 COD 以及外加碳源量)后,GUI 能够自动预测并优化出水总氮、能耗和外加碳源(ECS)的使用。

Water Quality Parameters(水质参数)
| 参数 | 范围 |
|---|---|
| Influent NH₄⁺-N | (5.4 - 60.7 mg/L) |
| Influent TN | (9.8 - 108.0 mg/L) |
| TN of Zone 5 | (4.8 - 44.6 mg/L) |
| TN of Zone 6 | (3.0 - 42.3 mg/L) |
| TN of Zone 7 | (2.8 - 38.9 mg/L) |
Controllable Parameters(可控参数)
| 参数 | 范围 |
|---|---|
| Influent Flowrate | (0 - 69970.0 m³/d) |
| DO of Zone 5 | (0.18 - 15.9 mg/L) |
| COD of Zone 6 | (10.1 - 240.0 mg/L) |
| DO of Zone 7 | (0.07 - 9.8 mg/L) |
| COD of Zone 7 | (6.9 - 132.0 mg/L) |
| External Carbon Source | (0 - 15.3 m³/d) |
Suggested Parameters(建议参数)
| 参数 | 建议值 |
|---|---|
| Influent Flowrate | (0 - 69970.0 m³/d) |
| DO of Zone 5 | (5.8 - 8.8 mg/L) |
| COD of Zone 6 | (28.0 - 35.5 mg/L) |
| DO of Zone 7 | (0.3 - 2.8 mg/L) |
| COD of Zone 7 | (0.9 - 26.4 mg/L) |
| External Carbon Source | (1.9 - 2.3 m³/d) |
操作按钮
- Predict and Optimize(预测与优化):绿色按钮
- Reset(重置):橙色按钮
结果输出区域
- Original Effluent TN (mg/L):原始出水总氮
- Optimized Effluent TN (mg/L):优化后出水总氮
- Original Energy Consumption (kWh):原始能耗
- Optimized Energy Consumption (kWh):优化后能耗
- Energy Savings (kWh):节能量
- Carbon Source Savings (m³/d):碳源节省量
- Optimal Parameters Combination:(最优参数组合):下方预留显示区域
图 S8 展示了该 GUI 系统在实际应用场景下的分析与优化策略。研究收集了未参与模型训练和测试的独立数据,通过 GUI 进行了进一步的模型验证。为了在强化脱氮的同时兼顾能耗与 COD 投药量的减少,建议根据 PDP 识别出的区间进行工艺优化。例如,通过优化关键参数,出水总氮浓度从 14.29 mg/L 降至 11.59 mg/L,污水处理厂能耗每天减少了 128.66 kWh,COD 投加浓度降低了 34.29 mg/L,对应外加碳源投加量从 3.72 m³/d降至 2.25 m³/d(以 1200 kg COD/m³ ECS 计)。随后,GUI 基于 365 天内不同特性的进水数据自动计算了脱氮提升、能耗及 COD 减量效果,实现了出水总氮、能耗和外加碳源使用的同步降低。值得注意的是,全年的出水总氮浓度平均下降了 17.50%,而 COD 投药量减少了 33.29%。
图 6b 展示了 365 天内优化前后的出水总氮浓度对比,优化后的总氮值始终低于优化前,表明 GUI 提供的参数组合有效提升了脱氮效果。能耗是污水处理厂脱氮优化中的关键因素。尽管已有研究建立了出水总氮和能耗的预测模型,但未能实现两者的同步优化。本研究采用 NSGA-II 模型对出水化学需氧量和总能耗进行多目标优化,实现了水质改善与节能的协同增效。结果表明,通过调整工艺运行参数,可以有效平衡能耗与 COD 投药量的削减,实现协调优化。这些研究成果证明,该优化控制策略能有效提升采用生态组合塘(ECPs)工艺的污水处理厂的脱氮性能,同时显著降低运行能耗和外加碳源的成本。

补充材料
附录内容清单
- 文本 S1:机器学习模型详述
- 文本 S2:多目标优化框架的建立
- 文本 S3:碳减排量的计算方法
- 图 S1:生态组合塘(ECPs)的平面布局图
- 图 S2:以出水总氮浓度为目标特征(基于 16 个初始参数)的六种机器学习模型训练图
- 图 S3:(a) 用于预测出水总氮(TN_eff)的 XGBoost 模型 SHAP 特征重要性分析(16 个初始参数);(b) 该模型的 SHAP 显著性分析
- 图 S4:特征与标签(目标变量)之间的 Pearson 相关性分析
- 图 S5:特征'外加碳源'的部分依赖图(PDP)
- 图 S6:其他特征的部分依赖图
- 图 S7:以能耗(EC)为目标特征的六种机器学习模型训练图
- 图 S8:用于预测与优化的图形用户界面(GUI)应用示例
- 表 S1:采用生态组合塘工艺的大型城市污水处理厂进水水质及设计出水水质指标
- 表 S2:训练及评估数据集的统计特性
- 表 S3:不同模型的性能指标对比
- 表 S4:基于 XGBoost 模型确定的强化脱氮且平衡能耗与 COD 减量的优化参数
- 表 S5:碳排放计算所采用的相关参数
文本 S1:机器学习模型详述
本研究对比了六种不同的机器学习模型,以评估其在污水处理厂总氮预测和能耗分析中的表现:
- 多元线性回归 (MLR):一种通过独立变量集捕捉因变量之间线性关系的统计方法。适用性:在变量间相互作用主要为线性时特别有效。
- 支持向量机 (SVM):其核心原则是识别能够最大化不同类别数据点之间间隔(Margin)的最佳超平面。优势:在处理原始特征空间中难以解决的高维数据任务时表现出色。
- 随机森林 (RF):一种基于分类和决策树回归的集成学习(Ensemble Learning)算法。特性:相比传统装袋法(Bagging),在处理小数据集和建模非线性关系方面更具优势。
- 轻量级梯度提升机 (LightGBM):由微软开发的基于直方图决策树的梯度提升框架。表现:训练速度快、准确度高,并能有效缓解模型过拟合问题。
- 类别特征提升 (CatBoost):基于梯度提升决策树(GBDT),专为有效处理异构数据和类别型(Categorical)数据而设计。稳定性:采用随机排列策略对数据排序,并利用权重系数减少低频和噪声数据的影响。
- 极端梯度提升 (XGBoost):集成多个梯度提升决策树,通过二阶梯度优化和正则化技术减少过拟合。适用范围:在小样本数据集上表现强劲,性能优于单体机器学习方法。
文本 S2:多目标优化框架的建立
本研究通过集成进化算法、评价模型与预测模型,构建了一个协同优化框架,旨在平衡出水水质与运行成本。
- 多目标优化(NSGA-II):采用简化的带策略非支配排序遗传算法(NSGA-II),解决出水总氮、能耗与碳源消耗之间的多目标优化问题。通过优化溶解氧、各区域 COD 以及外加碳源等运行参数,协调各目标间的复杂关系。
- TOPSIS 决策方法:利用逼近理想解排序法(TOPSIS)从 NSGA-II 生成的 Pareto 最优解集中筛选出最佳运行参数组合。基于目标函数值计算每个方案的 TOPSIS 评分,分值最高者即被确定为最优方案。
- 模型预测与优化流程:采用 XGBoost 回归模型预测出水总氮和能耗。通过加载预训练模型,并对输入数据进行标准化处理,以确保预测的准确性。初始化种群并设置交叉、变异及选择等遗传操作。当最优解的适应度在连续若干代内提升比例低于设定阈值时,进化停止。从最终的 Pareto 前沿中抽取样本,通过 TOPSIS 计算得出最优解。
- 图形用户界面 (GUI):构建了图形化界面,方便用户输入进水水质和工艺参数。系统首先预测原始的出水总氮和能耗数据,随后运行多次优化算法以锁定最优解。界面最终呈现优化后的总氮浓度、能耗、节能效果、碳源节省量以及最优参数组合。
代码复现
污水处理数据集特征说明表
| 列名 (Column Name) | 中文名称 | 物理含义与作用 (大白话解释) | 变量类型 |
|---|---|---|---|
| Influent NH4+-N | 进水氨氮浓度 | 脏水里的尿素/氨水含量。这是主要的污染物之一,进水里这个高了,后面的硝化反应压力就大。 | 输入变量 (环境干扰) |
| Influent TN | 进水总氮浓度 | 进水里所有氮的总和。包括氨氮、硝态氮和有机氮。这是必须要去除的核心污染物。 | 输入变量 (环境干扰) |
| Influent Flowrate | 进水流量 | 这一刻进来了多少水。流量大意味着水力停留时间短,处理难度增加,冲击负荷大。 | 输入变量 (环境干扰) |
| DO of Zone 5 | 5 号区溶解氧 | 第 5 个生化反应格里的氧气含量。通常 Zone 5 是好氧区,氧气要足够多,细菌才能把氨氮吃掉(硝化反应)。 | 状态变量 (过程控制) |
| TN of Zone 5 | 5 号区总氮 | 第 5 个生化反应格里的总氮浓度。用于监测反应进行到中间阶段时,氮去除了多少。 | 状态变量 |
| COD of Zone 6 | 6 号区 COD | 第 6 个生化反应格里的有机物含量。反映还有多少'食物'给细菌吃,对反硝化脱氮至关重要。 | 状态变量 |
| TN of Zone 6 | 6 号区总氮 | 第 6 个生化反应格里的总氮浓度。过程监控指标。 | 状态变量 |
| DO of Zone 7 | 7 号区溶解氧 | 第 7 个生化反应格里的氧气含量。通常是流程末端的好氧区,用于最后的把关。 | 状态变量 |
| COD of Zone 7 | 7 号区 COD | 第 7 个生化反应格里的有机物含量。 | 状态变量 |
| TN of Zone 7 | 7 号区总氮 |
项目结构
TNeff-GUI-master/
├── Data/ # 数据文件
│ ├── Data after deleting features.csv
│ └── Data.csv
├── Graphical User Interace (GUI)/ # 用户界面相关文件
│ ├── GUI.py # 基础 GUI 实现
│ ├── GUI_layout.py # 优化版 GUI 布局
│ ├── NSGA-II.py # 多目标优化算法
│ ├── TOPSIS.py # 多准则决策方法
│ ├── model_effluent_TN.json # 总氮预测模型
│ ├── model_energy_consumption.json # 能耗预测模型
│ ├── step 1.png # 使用步骤截图
│ └── step 2.png
├── Model Development - Visualization/ # 模型开发与可视化
│ ├── Catboost.py # CatBoost 模型
│ ├── LGBM.py # LightGBM 模型
│ ├── MLR.py # 多元线性回归模型
│ ├── RF.py # 随机森林模型
│ ├── SVM.py # 支持向量机模型
│ └── XGBoost.py # XGBoost 模型
├── Model Interpretability/ # 模型可解释性分析
│ ├── One-dimensional PDP.py # 一维部分依赖图
│ ├── SHAP.py # SHAP 值分析
│ └── Two-dimensional PDP.py # 二维部分依赖图
└── README.md # 项目说明文档
模型开发与可视化
#!/usr/bin/env python # coding: utf-8
# 导入机器学习、数据处理及可视化所需的库
from sklearn.model_selection import KFold, GridSearchCV, train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm
from sklearn.preprocessing import StandardScaler
import pickle
from xgboost import XGBRegressor
import shap
# --- 1. 数据加载与初步切分 ---
# 从 CSV 文件读取脱氮工艺数据集
file_path = r'data.csv'
df = pd.read_csv(file_path, encoding='GBK')
# 提取特征变量 (X) 和目标变量 (y,即出水 TN 浓度)
X = df.drop(columns='Effluent TN')
y = df['Effluent TN']
# 将数据划分为训练集 (80%) 和测试集 (20%)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)
# --- 2. 特征标准化 ---
# 使用 StandardScaler 进行标准化处理,确保不同量纲的参数对模型贡献公平
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 将标准化模型保存为 pickle 文件,以便后续在 GUI 界面中调用
with open('scaler.pkl', 'wb') as f:
pickle.dump(scaler, f)
# --- 3. 超参数优化 (Grid Search) ---
# 定义 XGBoost 的超参数搜索空间,包括树的数量、深度、学习率及正则化参数
param_grid = {
'n_estimators': [100, , , ],
: [, , , , ],
: [, , , ],
: [, , ],
: [, , ],
: [, , ],
: [, , ],
: [, , ]
}
base_model = XGBRegressor(objective=, random_state=)
grid_search = GridSearchCV(
estimator=base_model,
param_grid=param_grid,
scoring=,
cv=,
verbose=,
n_jobs=-
)
grid_search.fit(X_train_scaled, y_train)
best_params = grid_search.best_params_
()
(best_params)
xgboost_model = XGBRegressor(**best_params, objective=, random_state=)
kf = KFold(n_splits=, shuffle=, random_state=)
train_r2_scores, train_rmse_scores = [], []
test_r2_scores, test_rmse_scores = [], []
all_y_train_pred, all_y_test_pred = [], []
all_y_train_true, all_y_test_true = [], []
train_index, test_index kf.split(X_train_scaled):
X_train_fold, X_test_fold = X_train_scaled[train_index], X_train_scaled[test_index]
y_train_fold, y_test_fold = y_train.iloc[train_index], y_train.iloc[test_index]
X_train_part, X_val_part, y_train_part, y_val_part = train_test_split(
X_train_fold, y_train_fold, test_size=, random_state=)
xgboost_model.fit(X_train_part, y_train_part, eval_set=[(X_val_part, y_val_part)], early_stopping_rounds=, verbose=)
best_iteration = xgboost_model.best_iteration
xgboost_model.n_estimators = best_iteration
xgboost_model.fit(X_train_fold, y_train_fold)
y_train_pred = xgboost_model.predict(X_train_fold)
y_test_pred = xgboost_model.predict(X_test_fold)
all_y_train_pred.extend(y_train_pred)
all_y_test_pred.extend(y_test_pred)
all_y_train_true.extend(y_train_fold.values)
all_y_test_true.extend(y_test_fold.values)
train_r2_scores.append(r2_score(y_train_fold, y_train_pred))
train_rmse_scores.append(np.sqrt(mean_squared_error(y_train_fold, y_train_pred)))
test_r2_scores.append(r2_score(y_test_fold, y_test_pred))
test_rmse_scores.append(np.sqrt(mean_squared_error(y_test_fold, y_test_pred)))
()
()
plt.figure(figsize=(, ), dpi=)
plt.scatter(all_y_train_true, all_y_train_pred, edgecolors=, c=, marker=, s=, alpha=, label=)
plt.scatter(all_y_test_true, all_y_test_pred, edgecolors=, c=, marker=, s=, alpha=, label=)
X_plot = np.array(all_y_test_true).reshape(-, )
y_plot_pred = np.array(all_y_test_pred)
sorted_idx = np.argsort(X_plot.flatten())
X_sorted = X_plot[sorted_idx]
y_sorted = y_plot_pred[sorted_idx]
linear_model = sm.OLS(y_sorted, sm.add_constant(X_sorted)).fit()
y_pred_line = linear_model.predict(sm.add_constant(X_sorted))
predictions_summary = linear_model.get_prediction(sm.add_constant(X_sorted)).summary_frame(alpha=)
plt.plot(X_sorted, y_pred_line, color=, linewidth=, label=)
plt.fill_between(X_sorted.flatten(), predictions_summary[], predictions_summary[], color=, alpha=, label=)
plt.plot([, ], [, ], c=, linestyle=, label=)
plt.legend(); plt.show()
explainer = shap.Explainer(xgboost_model, X_train_scaled)
shap_values = explainer(X_train_scaled)
shap.summary_plot(shap_values, X_train_scaled, feature_names=X_train.columns)
可能缺少这些库,可以按照要求安装
pip install statsmodels
pip install xgboost
pip install shap
模型可解释性
SHAP 可解释性
#!/usr/bin/env python # coding: utf-8
# In[ ]:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from xgboost import XGBRegressor
import numpy as np
import matplotlib.pyplot as plt
import shap
# Load dataset
file_path = r'D:\vscode-water\TNeff-GUI-master\Modelset\Data.csv'
df = pd.read_csv(file_path, encoding='GBK')
# Split features and target
X = df.drop(columns='Effluent TN')
y = df['Effluent TN']
# Train-test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Initialize XGBoost model
xgboost_model = XGBRegressor(
objective='reg:squarederror',
n_estimators=1000,
max_depth=6,
learning_rate=0.01,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
# Model training
xgboost_model.fit(X_train, y_train)
# Plot feature importance
feature_importances = xgboost_model.feature_importances_
sorted_idx = np.argsort(feature_importances)[::-1]
plt.figure(figsize=(12, 8))
plt.bar(range(len(feature_importances)), feature_importances[sorted_idx],, color='deepskyblue', alpha=0.3)
plt.xticks(range((feature_importances)), [X.columns[i] i sorted_idx], rotation=, fontsize=)
plt.title(, fontsize=)
plt.xlabel(, fontsize=)
plt.ylabel(, fontsize=)
plt.show()
explainer = shap.TreeExplainer(xgboost_model)
shap_values = explainer.shap_values(X_train)
shap.summary_plot(shap_values, X_train, feature_names=X.columns)

单变量的 PDP
#!/usr/bin/env python # coding: utf-8
# In[ ]:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from xgboost import XGBRegressor
from sklearn.model_selection import train_test_split
from sklearn.inspection import partial_dependence
from scipy.interpolate import splev, splrep
# Read data from CSV file
file_path = r'D:\vscode-water\TNeff-GUI-master\Modelset\Data.csv'
df = pd.read_csv(file_path, encoding='GBK')
# Split features and target
X = df.drop(columns='Effluent TN')
y = df['Effluent TN']
# Split dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Initialize XGBoost model
xgboost_model = XGBRegressor(
objective='reg:squarederror',
n_estimators=1000,
max_depth=6,
learning_rate=0.01,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
# Train the model
xgboost_model.fit(X_train, y_train)
# List of features to plot
features_to_plot = [
'External Carbon Source',
'COD of Zone 6',
'COD of Zone 7',
'DO of Zone 7',
'DO of Zone 5',
,
,
,
,
,
,
]
sns.set_theme(style=, palette=, font_scale=)
():
pdp = partial_dependence(xgboost_model, X_train, [feature], kind=, grid_resolution=)
plot_x = pd.Series(pdp.grid_values[]).rename()
plot_y = pd.Series(pdp.average[]).rename()
plot_i = pdp.individual[]
tck = splrep(plot_x, plot_y, s=)
xnew = np.linspace(plot_x.(), plot_x.(), )
ynew = splev(xnew, tck, der=)
fig, ax = plt.subplots(figsize=(, ))
a plot_i:
a_series = pd.Series(a)
df_i = pd.concat([plot_x, a_series.rename()], axis=)
sns.lineplot(data=df_i, x=, y=, color=, linewidth=, linestyle=, alpha=, ax=ax)
ax.plot(xnew, ynew, color=, linewidth=, label=)
std_error = np.std(plot_y) / np.sqrt((plot_y))
lower_bound = plot_y - * std_error
upper_bound = plot_y + * std_error
ax.fill_between(plot_x, lower_bound, upper_bound, color=, alpha=, label=)
sns.rugplot(data=X_train.sample(), x=feature, height=, color=, alpha=, ax=ax)
ax.set_ylabel()
ax.set_xlabel(feature)
x_min = plot_x.() - *(plot_x.() - plot_x.())
x_max = plot_x.() + *(plot_x.() - plot_x.())
ax.set_xlim(x_min, x_max)
ax.legend()
plt.savefig(, dpi=, bbox_inches=)
plt.show()
feature features_to_plot:
plot_pdp(feature)
#!/usr/bin/env python # coding: utf-8
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from xgboost import XGBRegressor
from sklearn.model_selection import train_test_split
from sklearn.inspection import partial_dependence
from scipy.interpolate import splev, splrep
# 读取数据
file_path = r'D:\vscode-water\TNeff-GUI-master\Modelset\Data.csv'
df = pd.read_csv(file_path, encoding='GBK')
# 分离特征和目标变量
X = df.drop(columns='Effluent TN')
y = df['Effluent TN']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 初始化 XGBoost 模型
xgboost_model = XGBRegressor(
objective='reg:squarederror',
n_estimators=1000,
max_depth=6,
learning_rate=0.01,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
# 训练模型
xgboost_model.fit(X_train, y_train)
# 需要绘制 PDP 图的特征列表
features_to_plot = [
'External Carbon Source',
'COD of Zone 6',
'COD of Zone 7',
'DO of Zone 7',
'DO of Zone 5',
'Influent NH4+-N',
,
,
,
,
,
]
sns.set_theme(style=, palette=, font_scale=)
():
pdp = partial_dependence(xgboost_model, X_train, [feature], kind=, grid_resolution=)
plot_x = pd.Series(pdp.grid_values[]).rename()
plot_y = pd.Series(pdp.average[]).rename()
plot_i = pdp.individual[]
std_dev = np.std(plot_i, axis=)
tck = splrep(plot_x, plot_y, s=)
xnew = np.linspace(plot_x.(), plot_x.(), )
ynew = splev(xnew, tck, der=)
fig, ax = plt.subplots(figsize=(, ))
ax.fill_between(plot_x, plot_y - std_dev, plot_y + std_dev, color=, alpha=, linewidth=)
ax.fill_between(plot_x, plot_y - * std_dev, plot_y + * std_dev, color=, alpha=, linewidth=)
ax.plot(plot_x, plot_y, color=, linestyle=, linewidth=, zorder=)
ax.plot(xnew, ynew, color=, linewidth=, label=, zorder=)
sns.rugplot(data=X_train.sample((, (X_train))), x=feature, height=, color=, alpha=, ax=ax)
feature == :
box_x_start =
box_width =
box_y_start = plot_y.() -
box_height = (plot_y.() - plot_y.()) +
rect = patches.Rectangle((box_x_start, box_y_start), box_width, box_height, linewidth=, edgecolor=, facecolor=, linestyle=, zorder=)
ax.add_patch(rect)
ax.set_ylabel()
feature feature feature feature:
ax.set_xlabel()
:
ax.set_xlabel(feature)
x_range = plot_x.() - plot_x.()
ax.set_xlim(plot_x.() - * x_range, plot_x.() + * x_range)
plt.savefig(, dpi=, bbox_inches=)
plt.show()
plt.close()
feature features_to_plot:
()
plot_pdp_journal_style(feature)
()

#!/usr/bin/env python # coding: utf-8
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from xgboost import XGBRegressor
from sklearn.model_selection import train_test_split
from sklearn.inspection import partial_dependence
from scipy.interpolate import splev, splrep
# 1. 读取数据 (请确保路径正确)
file_path = r'D:\vscode-water\TNeff-GUI-master\Modelset\Data.csv'
df = pd.read_csv(file_path, encoding='GBK')
# 2. 分离特征和目标变量
X = df.drop(columns='Effluent TN')
y = df['Effluent TN']
# 3. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 4. 初始化并训练 XGBoost 模型
xgboost_model = XGBRegressor(
objective='reg:squarederror',
n_estimators=1000,
max_depth=6,
learning_rate=0.01,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
xgboost_model.fit(X_train, y_train)
# 5. 定义需要绘制 PDP 图的特征列表
features_to_plot = [
'External Carbon Source',
'COD of Zone 6',
'COD of Zone 7',
'DO of Zone 7',
'DO of Zone 5',
'Influent NH4+-N',
,
,
,
,
,
]
sns.set_theme(style=, palette=, font_scale=)
():
pdp = partial_dependence(xgboost_model, X_train, [feature], kind=, grid_resolution=)
plot_x = pd.Series(pdp.grid_values[]).rename()
plot_y = pd.Series(pdp.average[]).rename()
plot_i = pdp.individual[]
std_dev = np.std(plot_i, axis=)
tck = splrep(plot_x, plot_y, s=)
xnew = np.linspace(plot_x.(), plot_x.(), )
ynew = splev(xnew, tck, der=)
fig, ax = plt.subplots(figsize=(, ))
ax.fill_between(plot_x, plot_y - std_dev, plot_y + std_dev, color=, alpha=, linewidth=)
ax.fill_between(plot_x, plot_y - * std_dev, plot_y + * std_dev, color=, alpha=, linewidth=)
ax.plot(plot_x, plot_y, color=, linestyle=, linewidth=, zorder=)
ax.plot(xnew, ynew, color=, linewidth=, label=, zorder=)
sns.rugplot(data=X_train.sample((, (X_train))), x=feature, height=, color=, alpha=, ax=ax)
feature == :
box_x_start =
box_width =
box_y_start = plot_y.() -
box_height = (plot_y.() - plot_y.()) +
rect = patches.Rectangle((box_x_start, box_y_start), box_width, box_height, linewidth=, edgecolor=, facecolor=, linestyle=, zorder=)
ax.add_patch(rect)
ax.set_ylabel()
(keyword feature keyword [, , , , ]):
ax.set_xlabel()
feature:
ax.set_xlabel()
feature:
ax.set_xlabel()
:
ax.set_xlabel(feature)
x_range = plot_x.() - plot_x.()
ax.set_xlim(plot_x.() - * x_range, plot_x.() + * x_range)
plt.savefig(, dpi=, bbox_inches=)
plt.show()
plt.close()
()
feature features_to_plot:
()
plot_pdp_journal_style(feature)
()
双变量的 PDP
#!/usr/bin/env python # coding: utf-8
# In[ ]:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from xgboost import XGBRegressor
from sklearn.model_selection import train_test_split
from sklearn.inspection import PartialDependenceDisplay
# Load dataset
file_path = r'D:\vscode-water\TNeff-GUI-master\Modelset\Data.csv'
df = pd.read_csv(file_path, encoding='GBK')
# Split features and target
X = df.drop(columns='Effluent TN')
y = df['Effluent TN']
# Split dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Initialize XGBoost model
xgboost_model = XGBRegressor(
objective='reg:squarederror',
n_estimators=1000,
max_depth=6,
learning_rate=0.01,
subsample=0.8,
colsample_bytree=0.8,
random_state=42
)
# Train the model
xgboost_model.fit(X_train, y_train)
# Feature selection and plot 2D PDP,Complementing other target features and related features
target_feature = 'External Carbon Source'
related_features = ['COD of Zone 6', 'COD of Zone 7']
for feature in related_features:
if feature == target_feature:
feature_idx = X.columns.get_loc(feature)
target_idx = X.columns.get_loc(target_feature)
plt.figure(figsize=(, ))
PartialDependenceDisplay.from_estimator(
xgboost_model,
X_train,
[(target_idx, feature_idx)],
feature_names=X.columns,
kind=
)
plt.title()
plt.show()

TOPSIS
import numpy as np
# 你的原始代码 (保持完全不变)
def topsis(data, weights):
if len(data) == 0:
return np.array([])
if data.ndim == 1:
data = data.reshape(1, -1)
norm_data = (data - data.min(axis=0)) / (data.max(axis=0) - data.min(axis=0) + 1e-10)
weighted_data = norm_data * weights
ideal_best = np.min(weighted_data, axis=0)
ideal_worst = np.max(weighted_data, axis=0)
dist_best = np.sqrt(np.sum((weighted_data - ideal_best) ** 2, axis=1))
dist_worst = np.sqrt(np.sum((weighted_data - ideal_worst) ** 2, axis=1))
scores = dist_worst / (dist_best + dist_worst + 1e-10)
return scores
# ==========================================
# 下面是调用示例
# ==========================================
# 1. 准备备选方案数据
# 每行代表一个方案(如 NSGA-II 的不同解)
# 列分别是:[出水 TN, 能耗,外加碳源]
# 注意:基于你的代码逻辑,这里的数值都是越小越好
data = np.array([
[12.5, 300, 50], # 策略 1:TN 偏高,但能耗和碳源极省
[10.0, 450, 80],
[, , ],
[, , ]
])
weights = np.array([, , ])
scores = topsis(data, weights)
()
i, score (scores):
()
best_index = np.argmax(scores)
()

NSGA-II.py
import numpy as np
import random
from deap import base, creator, tools, algorithms
import xgboost as xgb
import pandas as pd
from sklearn.preprocessing import StandardScaler
# ==========================================
# 1. 默认数据与变量范围设定
# ==========================================
# 默认工况数据:代表污水厂当前的实际运行状态(包含不可控的进水参数,和当前的操作参数)
default_data = {
'Influent NH4+-N': 29.6, # 进水氨氮 (固定参数)
'Influent TN': 35.9, # 进水总氮 (固定参数)
'Influent Flowrate': 38808.4, # 进水流量 (固定参数)
'DO of Zone 5': 7.1, # 5 区溶解氧 (控制变量)
'TN of Zone 5': 22.2, # 5 区总氮 (状态变量)
'COD of Zone 6': 55.0, # 6 区 COD (控制变量)
'TN of Zone 6': 13.8, # 6 区总氮 (状态变量)
'DO of Zone 7': 4.06, # 7 区溶解氧 (控制变量)
'COD of Zone 7': 31.9, # 7 区 COD (控制变量)
'TN of Zone 7': 11.7, # 7 区总氮 (状态变量)
'External Carbon Source': 3.3 # 外加碳源 (控制变量)
}
# 优化变量边界:定义遗传算法在搜索最佳操作参数时,不能超过的工艺极限
variable_ranges = [
(, ),
(, ),
(, ),
(, ),
(, )
]
df = pd.DataFrame([default_data])
scaler = StandardScaler()
scaler.fit(df)
model_tn = xgb.Booster()
model_power = xgb.Booster()
prediction_cache = {}
():
data.ndim == :
key = (data)
data = data.reshape(, -)
:
model_power.predict(xgb.DMatrix(data)), model_tn.predict(xgb.DMatrix(data))
key prediction_cache:
np.array([prediction_cache[key][]]), np.array([prediction_cache[key][]])
dmatrix = xgb.DMatrix(data)
pred_energy = model_power.predict(dmatrix)
pred_tn = model_tn.predict(dmatrix)
prediction_cache[key] = (pred_energy[], pred_tn[])
pred_energy, pred_tn
():
full_input = np.concatenate([fixed_water_params, individual])
energy, tn = predict_outputs(np.array(full_input))
delta_energy = energy[] - true_energy
delta_tn = tn[] - true_tn
delta_energy, delta_tn
():
(creator, ):
creator.create(, base.Fitness, weights=(-, -))
(creator, ):
creator.create(, , fitness=creator.FitnessMin)
toolbox = base.Toolbox()
toolbox.register(, : [random.uniform(r[], r[]) r variable_ranges])
toolbox.register(, tools.initIterate, creator.Individual, toolbox.attr_float)
toolbox.register(, tools.initRepeat, , toolbox.individual)
toolbox.register(, tools.cxSimulatedBinaryBounded, low=[r[] r variable_ranges], up=[r[] r variable_ranges], eta=)
():
individual = tools.mutPolynomialBounded(individual, low=[r[] r variable_ranges], up=[r[] r variable_ranges], eta=, indpb=)[]
i ((individual)):
low, up = variable_ranges[i]
individual[i] = (low, (up, individual[i]))
(individual[i], ) np.isnan(individual[i]) np.isinf(individual[i]):
individual[i] = (low + up) /
individual,
toolbox.register(, custom_mutate)
toolbox.register(, tools.selNSGA2)
full_input = np.concatenate([fixed_water_params, initial_operating_params])
true_energy, true_tn = predict_outputs(full_input)
():
evaluate(ind, fixed_water_params, true_energy[], true_tn[])
toolbox.register(, fitness_func)
pop = toolbox.population(n=)
pop[][:] = initial_operating_params.copy()
ind pop:
ind.fitness.values = toolbox.evaluate(ind)
hof = tools.ParetoFront()
hof.update(pop)
best_fitness = ([ind.fitness.values[] ind pop])
stall_count =
gen ():
offspring = algorithms.varOr(pop, toolbox, lambda_=, cxpb=, mutpb=)
ind offspring:
ind.fitness.valid:
ind.fitness.values = toolbox.evaluate(ind)
pop = toolbox.select(pop + offspring, k=)
hof.update(pop)
current_best = ([ind.fitness.values[] ind pop])
current_best < best_fitness * :
best_fitness = current_best
stall_count =
:
stall_count +=
stall_count >= :
n_samples = (, (hof))
pareto_samples = [hof[i] i np.linspace(, (hof) - , n_samples, dtype=)]
pareto_samples, true_energy[], true_tn[]
模型可视化
#!/usr/bin/env python # coding: utf-8
import tkinter as tk
from tkinter import ttk
import xgboost as xgb
import pandas as pd
from sklearn.preprocessing import StandardScaler
# 1. 默认数据字典:定义了进水参数、各生化池状态以及外部碳源的基准值
# 当用户在 GUI 中没有输入任何值时,系统会默认使用这些数值进行预测
default_data = {
'Influent NH4+-N': 29.6, # 进水氨氮
'Influent TN': 35.9, # 进水总氮
'Influent Flowrate': 38808.4, # 进水流量
'DO of Zone 5': 7.1, # 5 区溶解氧
'TN of Zone 5': 22.2, # 5 区总氮
'COD of Zone 6': 55.0, # 6 区化学需氧量
'TN of Zone 6': 13.8, # 6 区总氮
'DO of Zone 7': 4.06, # 7 区溶解氧
'COD of Zone 7': 31.9, # 7 区化学需氧量
'TN of Zone 7': 11.7, # 7 区总氮
'External Carbon Source': 3.3 # 外加碳源量
}
# 将默认数据转换为 Pandas DataFrame 格式,方便后续处理
df = pd.DataFrame([default_data])
# 2. 数据标准化处理
scaler = StandardScaler()
scaler.fit(df)
# 3. 加载预训练的 XGBoost 模型
model_tn = xgb.Booster()
model_tn.load_model()
model_power = xgb.Booster()
model_power.load_model()
():
:
(value)
ValueError:
run_count =
first_external_carbon_source =
():
run_count, first_external_carbon_source
run_count =
first_external_carbon_source =
entry feature_entry_map.values():
entry.delete(, tk.END)
original_tn.()
original_power.()
optimized_tn.()
optimized_power.()
energy_savings_var.()
carbon_savings_var.()
output_text.()
():
run_count, first_external_carbon_source
run_count >= :
output_text.()
inputs = []
feature, entry feature_entry_map.items():
value = entry.get().strip()
value:
inputs.append(default_data[feature])
:
validated = validate_input(value)
validated :
output_text.()
inputs.append(validated)
:
inputs_df = pd.DataFrame([inputs], columns=default_data.keys())
inputs_scaled = scaler.transform(inputs_df)
dmatrix = xgb.DMatrix(inputs_scaled)
effluent_tn_pred = model_tn.predict(dmatrix)[]
power_consumption_pred = model_power.predict(dmatrix)[]
run_count == :
original_tn.()
original_power.()
first_external_carbon_source = inputs_df[].iloc[]
run_count == :
optimized_tn.()
optimized_power.()
original_power_value = (original_power.get()) original_power.get()
energy_savings = original_power_value - power_consumption_pred
energy_savings_var.()
second_external_carbon_source = inputs_df[].iloc[]
carbon_savings = first_external_carbon_source - second_external_carbon_source
carbon_savings_var.()
run_count +=
Exception e:
output_text.()
units = {
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
:
}
root = tk.Tk()
root.title()
root.geometry()
root.configure(bg=)
default_font = (, )
main_frame = tk.Frame(root, bg=, padx=, pady=)
main_frame.pack(expand=)
title_label = tk.Label(main_frame, text=, font=(, , ), bg=)
title_label.grid(row=, column=, columnspan=, pady=)
left_labels = [
(, ),
(, ),
(, ),
(, ),
(, )
]
right_labels = [
(, ),
(, ),
(, ),
(, ),
(, ),
(, )
]
feature_entry_map = {}
tk.Label(main_frame, text=, font=(, , ), bg=).grid(row=, column=, columnspan=, pady=)
i, (label, feature) (left_labels, start=):
tk.Label(main_frame, text=label, font=default_font, bg=).grid(row=i, column=, padx=, pady=, sticky=)
entry = tk.Entry(main_frame, font=default_font, width=)
entry.grid(row=i, column=, padx=, pady=, sticky=)
feature_entry_map[feature] = entry
unit_text = units.get(feature, )
tk.Label(main_frame, text=, font=default_font, bg=).grid(row=i, column=, padx=, pady=, sticky=)
tk.Label(main_frame, text=, font=(, , ), bg=).grid(row=, column=, columnspan=, pady=)
i, (label, feature) (right_labels, start=):
tk.Label(main_frame, text=label, font=default_font, bg=).grid(row=i, column=, padx=, pady=, sticky=)
entry = tk.Entry(main_frame, font=default_font, width=)
entry.grid(row=i, column=, padx=, pady=, sticky=)
feature_entry_map[feature] = entry
unit_text = units.get(feature, )
tk.Label(main_frame, text=, font=default_font, bg=).grid(row=i, column=, padx=, pady=, sticky=)
original_tn = tk.StringVar()
original_power = tk.StringVar()
optimized_tn = tk.StringVar()
optimized_power = tk.StringVar()
energy_savings_var = tk.StringVar()
carbon_savings_var = tk.StringVar()
output_text = tk.StringVar()
predict_button = tk.Button(main_frame, text=, font=(, ), command=predict, bg=, fg=, width=)
predict_button.grid(row=, column=, columnspan=, pady=)
reset_button = tk.Button(main_frame, text=, font=(, ), command=clear_inputs, bg=, fg=, width=)
reset_button.grid(row=, column=, columnspan=, pady=)
output_frame = tk.Frame(main_frame, bg=)
output_frame.grid(row=, column=, columnspan=, padx=, pady=)
tk.Label(output_frame, text=, font=default_font, bg=).grid(row=, column=, sticky=)
tk.Entry(output_frame, textvariable=original_tn, font=default_font, state=).grid(row=, column=)
tk.Label(output_frame, text=, font=default_font, bg=).grid(row=, column=, sticky=)
tk.Entry(output_frame, textvariable=optimized_tn, font=default_font, state=).grid(row=, column=)
tk.Label(output_frame, text=, font=default_font, bg=).grid(row=, column=, sticky=)
tk.Entry(output_frame, textvariable=original_power, font=default_font).grid(row=, column=)
tk.Label(output_frame, text=, font=default_font, bg=).grid(row=, column=, sticky=)
tk.Entry(output_frame, textvariable=optimized_power, font=default_font, state=).grid(row=, column=)
tk.Label(output_frame, text=, font=default_font, bg=).grid(row=, column=, sticky=)
tk.Entry(output_frame, textvariable=energy_savings_var, font=default_font, state=).grid(row=, column=)
tk.Label(output_frame, text=, font=default_font, bg=).grid(row=, column=, sticky=)
tk.Entry(output_frame, textvariable=carbon_savings_var, font=default_font, state=).grid(row=, column=)
output_label = tk.Label(output_frame, textvariable=output_text, font=default_font, bg=, fg=)
output_label.grid(row=, column=, columnspan=)
root.mainloop()



