【时序预测】之水质净化厂工艺控制-曝气量预测(上)

简介: 【时序预测】之水质净化厂工艺控制-曝气量预测(上)

一、【时序预测】之水质净化厂工艺控制-曝气量预测


竞赛地址: www.datafountain.cn/competition…


1.大赛背景


为推进智慧水务建设,激发数字化创新能力,助力创新应用挖掘与落地,加快水务行业现代化进程,深圳市环境水务集团有限公司发起主办首届“深水云脑杯”智慧水务数据创新大赛。深水渠成,群智创新!本届大赛将以数字化创新模式为抓手,把握发展脉搏、汇聚产学研力量,成为汇聚大数据、人工智能等数据智能相关信息技术在水务领域应用创新的擂台,揭榜挂帅,推动赛事成果转化,解决社会和行业聚焦的难题,促进水务行业实现智慧升级及高质量发展。


2.  赛题背景


当今社会,水资源匮乏的问题越来越突出,污水处理是解决水资源匮乏的有效手段之一。膜生物反应器(MBR)工艺作为近年来的一种新型污水工艺,较传统的活性污泥法来说,具有占地面积小,产水水质高、剩余污泥少、自控程度高等优势,在用地资源日益紧张的今天,MBR工艺在全国各地的污水处理厂均得到了一定的应用。但同时,由于其基础造价较高、膜污染及能耗较高等问题,其进一步应用也得到了了一定的限制。以采用厌氧-缺氧-好氧生物脱氮除磷(A-A-O)耦合膜生物反应器工艺(A2O-MBR)的某污水厂为例,通过对各工艺段能耗进行对比分析,得出其生化段曝气能耗占全厂能耗的比例高达49%。从能量转换的角度来看,其实质是以能耗换取水质。


本次赛题主要是通过对采用A2O-MBR工艺的某污水厂运行过程中的历史数据,利用大数据建模,形成可供推理的智能曝气数理模型,通过算法迭代计算出最优曝气量。结合污水处理厂工艺流程,通过数学建模,建立污水厂精准曝气机理模型,实现生化处理系统运行效果的优化控制,在保障污水厂出水水质满足行标的前提下,采用智能化、自动化手段降低能耗,有效解决实际问题,助力市政污水处理行业低碳发展。


3.赛题任务


水质净化厂运营过程中,曝气量需根据进出水水质等参数实时进行调节,以保障出水水质达标,而在实际生产过程中,由于影响因素多,目前尚不能对曝气量进行精确控制,希望通过机器学习模型的应用预测曝气量,以指导实际生产。

image.png


4.数据简介


数据来源于使用A2O-MBR工艺的污水厂,生化池好氧段曝气生产环境。在生化池的好氧工艺段,我们通过控制曝气量,来改变水中的溶解氧(DO),将污水中的氨氮(NH4)转化成硝氮(NO3),同时将水中的有机物(COD)降解。


5.数据说明


  • 1.部分特征中的0值并不代表实际值。
  • 2.特征在邻近时序内数值未发生改变,通常是因为数据采集频率原因,并非生产环境中未发生显著改变。
  • 3.北生化池和南生化池在生产过程中不会互相影响。
time Label1 Label2
2022/7/18 2:40 0 0
2022/7/18 2:42 0 0
2022/7/18 2:44 0 0
2022/7/18 2:46 0 0
2022/7/18 2:48 0 0
2022/7/18 2:50 0 0
0 0


二、特征提取


1.lightgbm升级


lightgbm aistudio默认为3.1.1,许多方法不支持,建议升级最新版3.3.2.

!pip list | grep lightgbm 
lightgbm                       3.1.1
!pip install -U -q lightgbm
!pip list | grep lightgbm 
lightgbm                       3.3.2


2.导入常用库


2.1 gc库简介


gc模块即Python中垃圾回收模块,它提供可选的垃圾回收器的接口。同时提供对回收器找到但是无法释放的不可达对象的访问。由于 Python 使用了带有引用计数的回收器,如果你确定你的程序不会产生循环引用,你可以关闭回收器。可以通过调用 gc.disable() 关闭自动垃圾回收。

  • enable()             --启用自动垃圾回收。
  • disable()            --禁用自动垃圾回收。
  • isenabled()          --如果启用了自动收集,则返回true。
  • collect()            --立即执行完全收集。
  • get_count()          --返回当前集合计数。
  • get_stats()          --返回包含每代统计信息的词典列表。
  • set_debug()          --设置调试标志。
  • get_debug()          --获取调试标志。
  • set_threshold()      --设置收集阈值。
  • get_threshold()      --返回集合阈值的当前值。
  • get_objects()        --返回收集器跟踪的所有对象的列表。
  • is_tracked()         --如果跟踪给定对象,则返回true。
  • is_finalized()       --如果给定对象已定稿,则返回true。
  • get_referrers()      --返回引用对象的对象列表。
  • get_referents()      --返回对象引用的对象列表。
  • freeze()             --冻结所有跟踪对象,并在将来的收集中忽略它们。
  • unfreeze()           --解冻永久生成中的所有对象。
  • get_freeze_count()   --返回永久生成中的对象数。

最常用的方法:gc.collect() --立即执行完全收集,释放出不使用的资源,归还内存。可以通过参数generation,单独对0,1,2代进行回收释放。

例如:编写无限循环C程序:

#include<stdio.h>
int main(){
  while(1){
    printf("okok");
  }
  return 0;
}

编译备用

cc test.c -o test
!cc test.c -o test
import subprocess, psutil, gc
mem1 = psutil.virtual_memory()
print(f"某程序前内存已使用:{mem1.used}")
print(f"某程序前内存剩余:{mem1.free}")
print(f"某程序前内存百分比:{mem1.percent}")
app1 = subprocess.Popen('test')
app2 = subprocess.Popen(r'test')
app3 = subprocess.Popen(r'test')
mem2 = psutil.virtual_memory()
print(f"某程序后内存已使用:{mem2.used}")
print(f"某程序后内存剩余:{mem2.free}")
print(f"某程序后内存百分比:{mem2.percent}")
app1.kill()
app2.kill()
app3.kill()
gc.collect()
mem3 = psutil.virtual_memory()
print(f"GC回收后内存已使用:{mem3.used}")
print(f"GC回收后内存剩余:{mem3.free}")
print(f"GC回收后内存百分比:{mem3.percent}")
某程序前内存已使用:6770204672
某程序前内存剩余:68427513856
某程序前内存百分比:6.5
某程序后内存已使用:6771159040
某程序后内存剩余:68426559488
某程序后内存百分比:6.5
GC回收后内存已使用:6769913856
GC回收后内存剩余:68427763712
GC回收后内存百分比:6.5

需要注意的是:执行收集本身也需要一点的内存代价,所以可能存在收集完成后内存反而增加的情况。

image.png


2.2 tqdm介绍


2.2.1 不带参数


# 不带参数
from tqdm import tqdm
import time
for i in tqdm(range(50)):
    time.sleep(0.1)    
100%|██████████| 50/50 [00:05<00:00,  9.92it/s]


2.2.2 带参数


# 带参数
from tqdm import tqdm
import time
d = {'loss':0.2,'learn':0.8}
for i in tqdm(range(50),desc='进行中',ncols=100,postfix=d): #desc设置名称,ncols设置进度条长度.postfix以字典形式传入详细信息
    time.sleep(0.1)
进行中: 100%|█████████████████████████████████████| 50/50 [00:05<00:00,  9.89it/s, learn=0.8, loss=0.2]


2.2.3 处理列表


# 用tqdm处理列表中的对象,显示处理进度
from tqdm import tqdm
import time
bar = tqdm(['p1','p2','p3','p4','p5'])
for b in bar:
    time.sleep(0.5)
    bar.set_description("处理{0}中".format(b))
处理p5中: 100%|██████████| 5/5 [00:02<00:00,  1.99it/s]
import warnings
warnings.simplefilter('ignore')
import gc
import numpy as np
import pandas as pd
pd.set_option('display.max_columns', None)
from tqdm.auto import tqdm
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error
import lightgbm as lgb


2.3 rolling滑动窗口


为了提升数据的准确性,将某个点的取值扩大到包含这个点的一段区间,用区间来进行判断,这个区间就是窗口。移动窗口就是窗口向一端滑行,默认是从右往左,每次滑行并不是区间整块的滑行,而是一个单位一个单位的滑行。

例如:

import pandas as pd
s = [1,2,3,5,6,10,12,14,12,30]
pd.Series(s).rolling(window=3).mean()
0          NaN
1          NaN
2     2.000000
3     3.333333
4     4.666667
5     7.000000
6     9.333333
7    12.000000
8    12.666667
9    18.666667
dtype: float64

设置的窗口window=3,也就是3个数取一个均值。index 0,1 为NaN,是因为它们前面都不够3个数,等到index2 的时候,它的值是怎么算的呢,就是(index0+index1+index2 )/3 index3 的值就是( index1+index2+index3)/ 3

DataFrame.rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None)
  • window: 也可以省略不写。表示时间窗的大小,注意有两种形式(int or offset)。如果使用int,则数值表示计算统计量的观测值的数量即向前几个数据。如果是offset类型,表示时间窗的大小。offset详解
  • min_periods:每个窗口最少包含的观测值数量,小于这个值的窗口结果为NA。值可以是int,默认None。offset情况下,默认为1。
  • center: 把窗口的标签设置为居中。布尔型,默认False,居右
  • win_type: 窗口的类型。截取窗的各种函数。字符串类型,默认为None。各种类型
  • on: 可选参数。对于dataframe而言,指定要计算滚动窗口的列。值为列名。
  • axis: int、字符串,默认为0,即对列进行计算
  • closed:定义区间的开闭,支持int类型的window。对于offset类型默认是左开右闭的即默认为right。可以根据情况指定为left both等。


3.特征提取


train = pd.read_csv('data/data169443/train_dataset.csv')
test = pd.read_csv('data/data169443/evaluation_public.csv')
# 合并数据集
df = pd.concat([train,test])
roll_cols = ['JS_NH3',
 'CS_NH3',
 'JS_TN',
 'CS_TN',
 'JS_LL',
 'CS_LL',
 'MCCS_NH4',
 'MCCS_NO3',
 'JS_COD',
 'CS_COD',
 'JS_SW',
 'CS_SW',
 'B_HYC_NH4',
 'B_HYC_XD',
 'B_HYC_MLSS',
 'B_HYC_JS_DO',
 'B_HYC_DO',
 'B_CS_MQ_SSLL',
 'B_QY_ORP',
 'N_HYC_NH4',
 'N_HYC_XD',
 'N_HYC_MLSS',
 'N_HYC_JS_DO',
 'N_HYC_DO',
 'N_CS_MQ_SSLL',
 'N_QY_ORP']
df['time'] = pd.to_datetime(df['time'])
for i in range(1,5):
    df[[ii+f'_roll_{i}_mean_diff' for ii in roll_cols]] = df[roll_cols].rolling(i, min_periods=1).sum().diff()
df[[ii+'_roll_8_mean' for ii in roll_cols]] = df[roll_cols].rolling(8, min_periods=1).mean()
df[[ii+'_roll_16_mean' for ii in roll_cols]] = df[roll_cols].rolling(16, min_periods=1).mean()
df[[ii+'_roll_16_mean_diff' for ii in roll_cols]] = df[[ii+'_roll_16_mean' for ii in roll_cols]].diff()
df[[ii+'_roll_8_mean_diff' for ii in roll_cols]] = df[[ii+'_roll_8_mean' for ii in roll_cols]].diff()
df[[ii+'_roll_8_std' for ii in roll_cols]] = df[roll_cols].rolling(8, min_periods=1).std()
train = df.iloc[:train.shape[0]]
test = df.iloc[train.shape[0]:]
N_col = ['N_HYC_NH4',
 'N_HYC_XD',
 'N_HYC_MLSS',
 'N_HYC_JS_DO',
 'N_HYC_DO',
 'N_CS_MQ_SSLL',
 'N_QY_ORP']
B_col = ['B_HYC_NH4',
 'B_HYC_XD',
 'B_HYC_MLSS',
 'B_HYC_JS_DO',
 'B_HYC_DO',
 'B_CS_MQ_SSLL',
 'B_QY_ORP']
NB_col = ['A_'+ ii[2:] for ii in ['B_HYC_NH4',
 'B_HYC_XD',
 'B_HYC_MLSS',
 'B_HYC_JS_DO',
 'B_HYC_DO',
 'B_CS_MQ_SSLL',
 'B_QY_ORP']]
train[NB_col] = train[B_col].values/(train[N_col].values+ 1e-3)
test[NB_col] = test[B_col].values/(test[N_col].values+ 1e-3)
# NB_col
# 1. 数据说明里表示,北生化池和南生化池在生产过程中不会互相影响, 可以先试下分开两部分
# 2. 只用有 label 的数据
train_B = train[[i for i in train.columns if (i != 'Label2' and not i.startswith('N_'))]].copy()
train_N = train[[i for i in train.columns if (i != 'Label1' and not i.startswith('B_'))]].copy()
train_B = train_B[train_B['Label1'].notna()].copy().reset_index(drop=True)
train_N = train_N[train_N['Label2'].notna()].copy().reset_index(drop=True)
test_B = test[[i for i in test.columns if not i.startswith('N_')]].copy()
test_N = test[[i for i in test.columns if not i.startswith('B_')]].copy()
# 时间特征
def add_datetime_feats(df):
    df['time'] = pd.to_datetime(df['time'])
    df['day'] = df['time'].dt.day
    df['hour'] = df['time'].dt.hour
    df['dayofweek'] = df['time'].dt.dayofweek
    return df
train_B = add_datetime_feats(train_B)
train_N = add_datetime_feats(train_N)
test_B = add_datetime_feats(test_B)
test_N = add_datetime_feats(test_N)
# 做点比率数值特征
def add_ratio_feats(df, type_='B'):
    df['JS_CS_NH3_ratio'] = df['JS_NH3'] / (df['CS_NH3'] + 1e-3)
    df['JS_CS_TN_ratio'] = df['JS_TN'] / (df['CS_TN'] + 1e-3)
    df['JS_CS_LL_ratio']  = df['JS_LL'] / (df['CS_LL'] + 1e-3)
    df['MCCS_NH4_NH3_ratio'] = df['MCCS_NH4'] / (df['CS_NH3'] + 1e-3)
    df['MCCS_NO3_NH3_ratio'] = df['MCCS_NO3'] / (df['CS_NH3'] + 1e-3)
    df['JS_CS_COD_ratio'] = df['JS_COD'] / (df['CS_COD'] + 1e-3)
    df['JS_CS_SW_ratio'] = df['JS_SW'] / (df['CS_SW'] + 1e-3)
    df['HYC_DO_ratio'] = df[f'{type_}_HYC_JS_DO'] / (df[f'{type_}_HYC_DO'] + 1e-3)
    df['CS_MQ_LL_ratio'] = df[f'{type_}_CS_MQ_SSLL'] / (df['CS_LL'] + 1e-3)
    return df
train_B = add_ratio_feats(train_B, type_='B')
train_N = add_ratio_feats(train_N, type_='N')
test_B = add_ratio_feats(test_B, type_='B')
test_N = add_ratio_feats(test_N, type_='N')
# target log1p 转换
B_max, B_min = train_B['Label1'].max(), train_B['Label1'].min()
N_max, N_min = train_N['Label2'].max(), train_N['Label2'].min()
train_B['Label1'] = np.log1p(train_B['Label1'])
train_N['Label2'] = np.log1p(train_N['Label2'])


三、模型训练


需安装更新 tscv

----> 1 df_oof_B, pred_B = run_lgb(train_B, test_B, ycol='Label1',n_splits=10)
      2 df_oof_N, pred_N = run_lgb(train_N, test_N, ycol='Label2',n_splits=10)
/tmp/ipykernel_110/1103088436.py in run_lgb(df_train, df_test, ycol, n_splits, seed)
     15     prediction[ycol] = 0
     16     df_importance_list = []
---> 17     from tscv import GapKFold
     18     cv = GapKFold(n_splits=n_splits, gap_before=0, gap_after=0)
     19     for fold_id, (trn_idx, val_idx) in enumerate(cv.split(df_train[use_feats])):
ModuleNotFoundError: No module named 'tscv'
!pip install -U tscv 
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple
Collecting tscv
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b8/5f/dfdbec6c4441f484e15d1f89ff6f3cbb33009e67a282fa7f6d31d16de13a/tscv-0.1.2-py3-none-any.whl (18 kB)
Requirement already satisfied: scikit-learn>=0.22 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from tscv) (0.24.2)
Requirement already satisfied: numpy>=1.13.3 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from tscv) (1.19.5)
Requirement already satisfied: scipy>=0.19.1 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-learn>=0.22->tscv) (1.6.3)
Requirement already satisfied: threadpoolctl>=2.0.0 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-learn>=0.22->tscv) (2.1.0)
Requirement already satisfied: joblib>=0.11 in /opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages (from scikit-learn>=0.22->tscv) (0.14.1)
Installing collected packages: tscv
Successfully installed tscv-0.1.2
[notice] A new release of pip available: 22.1.2 -> 22.2.2
[notice] To update, run: pip install --upgrade pip


相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
目录
相关文章
|
6月前
GEE案例——一个完整的火灾监测案例dNBR差异化归一化烧毁指数
GEE案例——一个完整的火灾监测案例dNBR差异化归一化烧毁指数
174 0
|
6月前
|
算法 数据挖掘
R语言面板数据回归:含时间固定效应混合模型分析交通死亡率、酒驾法和啤酒税
R语言面板数据回归:含时间固定效应混合模型分析交通死亡率、酒驾法和啤酒税
车辆纵向动力学、加速性能和燃料消耗研究(Matlab代码实现)
车辆纵向动力学、加速性能和燃料消耗研究(Matlab代码实现)
|
6月前
|
机器学习/深度学习 算法 自动驾驶
集检测与分类于一身的LVLane来啦 | 正面硬刚ADAS车道线落地的困难点
集检测与分类于一身的LVLane来啦 | 正面硬刚ADAS车道线落地的困难点
181 0
|
机器学习/深度学习 传感器 算法
【地震】基于有限差分 (FDTD) 模拟地震超材料(晶体)时域分析附matlab代码
【地震】基于有限差分 (FDTD) 模拟地震超材料(晶体)时域分析附matlab代码
|
安全 调度
【电动车】主动配电网多源协同运行优化研究——大规模电动汽车的蒙特卡洛模拟(Matlab代码实现)
【电动车】主动配电网多源协同运行优化研究——大规模电动汽车的蒙特卡洛模拟(Matlab代码实现)
164 0
【电动车】主动配电网多源协同运行优化研究——大规模电动汽车的蒙特卡洛模拟(Matlab代码实现)
|
算法
【漂移-扩散通量重建 FV 方案】用于半导体和气体放电模拟的电子传输的更准确的 Sharfetter-Gummel 算法(Matlab代码实现)
【漂移-扩散通量重建 FV 方案】用于半导体和气体放电模拟的电子传输的更准确的 Sharfetter-Gummel 算法(Matlab代码实现)
105 0
|
算法 安全
车-电-路网时空分布负荷预测研究(Matlab代码)
车-电-路网时空分布负荷预测研究(Matlab代码)
115 0
|
存储 算法 数据中心
基于蓄电池进行调峰和频率调节研究【超线性增益的联合优化】(Matlab代码实现)
基于蓄电池进行调峰和频率调节研究【超线性增益的联合优化】(Matlab代码实现)
|
调度
混合动力电动车优化调度与建模(发动机,电机,电池组等组件建模)(Matlab代码实现)
混合动力电动车优化调度与建模(发动机,电机,电池组等组件建模)(Matlab代码实现)
108 0
下一篇
无影云桌面