news 2026/9/24 18:16:19

基于LSTM的景泰小区水产量预测与可视化全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于LSTM的景泰小区水产量预测与可视化全流程

简介:这份资源是面向数据科学学习者与机器学习入门者的完整项目源码,围绕景泰小区水产量预测场景,用LSTM长短期记忆网络对历史水量时间序列建模,解决未来水产量精准预测的问题。项目共156个文件,压缩包约16.74MB,以27个Python脚本承担数据处理、模型构建与训练预测,50个pth权重文件保存训练好的模型参数,另有19张png图表、15个yaml配置、6个html与6个js文件搭建网页交互界面,4个css样式表负责界面美化,并附带xlsx、csv、sqlite3等数据文件与readme、requirements说明。已有276人学习下载。读者可从中获得一套可直接运行的LSTM预测工程范例,理解时间序列建模、模型持久化、前后端页面联调与依赖配置的完整流程,适合作为课程设计、毕业设计或机器学习练手项目的参考模板。

1. 景泰小区水产量预测:从LSTM模型到可视化页面的完整落地

景泰小区的日供水量数据我盯了三个月,最头疼的不是模型精度,而是数据本身——每天一个采样点,一年才365条,遇到节假日和夏季高峰还会突变。用传统ARIMA跑出来的曲线总是慢半拍,直到换成LSTM才把滞后问题压下去。这个标题讲的就是用Python搭LSTM预测模型、用JavaScript和HTML/CSS做前端展示的完整方案,适合有Python基础、想跑通时序预测全链路的水务或物业数据从业者。整套东西不依赖云服务,本地就能跑,前端页面直接打开HTML文件即可查看预测结果。下面按数据准备、模型训练、前端对接、避坑、调优的顺序拆开讲。

2. 数据准备与LSTM输入构造:把日供水量变成监督学习样本

2.1 景泰小区数据长什么样,先做三件事

拿到手的原始数据通常是一张Excel表,两列:日期和当日供水量(单位立方米)。常见做法是先做三件事——缺失值检查、异常值剔除、按时间排序。景泰小区这种规模,日供水量一般在200到800立方米之间波动,如果某天出现0或者超过2000,基本是抄表故障或管道爆管,直接按前后三天的均值补上。

import pandas as pd import numpy as np # 读取原始数据,日期列解析为datetime df = pd.read_excel('jingtai_water.xlsx', parse_dates=['date']) df = df.sort_values('date').reset_index(drop=True) # 缺失值用前向填充,异常值用3倍标准差截断 df['water'] = df['water'].fillna(method='ffill') mean, std = df['water'].mean(), df['water'].std() df['water'] = df['water'].clip(mean - 3*std, mean + 3*std) # 检查是否有重复日期 assert df['date'].duplicated().sum() == 0, '存在重复日期' print(df.describe())

这段代码的逻辑是先保证时间轴连续且唯一,再做统计层面的清洗。clip用3倍标准差截断,比直接删除更稳,因为删掉后时间轴会断,后面构造滑动窗口时容易错位。参数上,ffill适合供水量这种变化平缓的序列,如果是气温类突变数据,用插值更合适。

2.2 滑动窗口构造:LSTM要的是三维张量

LSTM的输入不是一维序列,而是(样本数, 时间步长, 特征数)的三维张量。景泰小区单变量预测,特征数为1,时间步长决定用过去多少天预测下一天。我一般先用7天,因为供水有明显的周周期,周末和工作日模式不同。

def create_sequences(data, look_back=7): X, y = [], [] for i in range(len(data) - look_back): X.append(data[i:i+look_back]) y.append(data[i+look_back]) return np.array(X), np.array(y) # 归一化到0-1,LSTM对尺度敏感 from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler(feature_range=(0, 1)) scaled = scaler.fit_transform(df[['water']]) look_back = 7 X, y = create_sequences(scaled, look_back) # 重塑为 (样本, 时间步, 特征) X = X.reshape((X.shape[0], X.shape[1], 1)) print(X.shape, y.shape) # 例如 (358, 7, 1) (358,)

look_back=7意味着每个样本用前7天预测第8天。归一化必须用训练集的scaler去transform测试集,否则信息泄露,这是时序预测里最常见的翻车点。reshape那一步如果漏了,Keras会报维度错误,新手容易卡在这里。

2.3 训练集测试集切分:不能随机打乱

时序数据切分和普通机器学习不一样,绝对不能train_test_split(shuffle=True)。常见做法是按时间顺序,前80%做训练,后20%做测试。景泰小区三年数据约1095条,前876条训练,后219条测试。

split = int(len(X) * 0.8) X_train, X_test = X[:split], X[split:] y_train, y_test = y[:split], y[split:] # 反归一化函数,预测完要还原成实际水量 def inverse_transform(arr): return scaler.inverse_transform(arr.reshape(-1, 1)).flatten()

切分后训练集和测试集在时间上不重叠,测试集完全模拟“用历史预测未来”的场景。如果打乱,模型会看到未来数据,评估结果虚高,上线后直接崩。这个坑我在早期项目里踩过,血泪经验。

3. 用Python搭LSTM模型:结构、编译与训练参数怎么定

3.1 模型结构:两层LSTM加Dropout就够了

景泰小区数据量不大,不需要堆很深。我一般用两层LSTM,第一层返回序列给第二层,第二层只返回最后时间步,后面接Dropout和全连接。Dropout设0.2,防止过拟合。

from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout model = Sequential([ LSTM(64, return_sequences=True, input_shape=(look_back, 1)), Dropout(0.2), LSTM(32, return_sequences=False), Dropout(0.2), Dense(1) ]) model.compile(optimizer='adam', loss='mse', metrics=['mae']) model.summary()

第一层64个单元,第二层32个,这个配置在几百到几千条数据上比较稳。return_sequences=True是让第一层输出完整序列,第二层才能继续处理。如果两层都设False,第二层就没法接。损失函数用MSE,因为供水量预测对大小误差都敏感;如果更关注相对误差,可以换MAPE,但MAPE在水量接近0时会爆炸,景泰小区最低也有200左右,问题不大。

3.2 训练参数:epochs、batch_size和早停

训练不是越多越好。我一般设epochs=100,batch_size=16,加EarlyStopping监控验证损失,patience=10。这样既不会欠拟合,也不会白跑。

from tensorflow.keras.callbacks import EarlyStopping early_stop = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True) history = model.fit( X_train, y_train, epochs=100, batch_size=16, validation_split=0.1, callbacks=[early_stop], verbose=1 )

validation_split=0.1从训练集尾部再切10%做验证,不碰测试集。restore_best_weights=True保证训练结束后模型回到验证损失最低的那一轮,不用手动存checkpoint。batch_size=16在几百条样本上比32更稳,梯度更新更频繁,收敛曲线更平滑。

3.3 预测与评估:反归一化后看真实误差

训练完在测试集上预测,记得反归一化再算MAE和RMSE。景泰小区日供水量预测,MAE控制在30立方米以内算可用,超过50就要检查数据或调结构。

y_pred = model.predict(X_test) y_pred_inv = inverse_transform(y_pred) y_test_inv = inverse_transform(y_test) from sklearn.metrics import mean_absolute_error, mean_squared_error mae = mean_absolute_error(y_test_inv, y_pred_inv) rmse = np.sqrt(mean_squared_error(y_test_inv, y_pred_inv)) print(f'MAE: {mae:.2f}, RMSE: {rmse:.2f}')

反归一化必须用同一个scaler,且reshape成(-1,1)。如果预测结果全是0到1之间的小数,说明忘了反归一化,这是新手最常见的黑匣子问题。评估完可以把预测值和真实值存成JSON,给前端用。

import json result = { 'dates': df['date'].iloc[-len(y_test_inv):].dt.strftime('%Y-%m-%d').tolist(), 'actual': y_test_inv.tolist(), 'predicted': y_pred_inv.tolist() } with open('predict_result.json', 'w') as f: json.dump(result, f)

这个JSON就是前后端的接口文件,前端用fetch读取后画图。日期格式统一成YYYY-MM-DD,避免JavaScript解析时区问题。

4. 前端展示:HTML/CSS/JavaScript怎么接LSTM预测结果

4.1 页面结构:一个canvas加一个数据表格

前端不复杂,一个HTML文件,引入Chart.js画折线图,下面放表格显示每日预测值。CSS负责居中布局和响应式,JavaScript负责读取JSON并渲染。

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>景泰小区水产量预测</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <style> body { display: flex; flex-direction: column; align-items: center; font-family: sans-serif; } .chart-container { width: 80%; max-width: 900px; margin: 20px auto; } table { border-collapse: collapse; width: 80%; max-width: 900px; } th, td { border: 1px solid #ccc; padding: 8px; text-align: center; } th { background: #f5f5f5; } </style> </head> <body> <h2>景泰小区日供水量预测</h2> <div class="chart-container"> <canvas id="waterChart"></canvas> </div> <table id="dataTable"> <thead><tr><th>日期</th><th>实际值</th><th>预测值</th></tr></thead> <tbody></tbody> </table> <script src="app.js"></script> </body> </html>

body用flex纵向居中,chart-container限制最大宽度,避免大屏上图表拉太长。表格样式简单,重点是数据可读。Chart.js从CDN引入,本地打开也能用,只要网络能访问CDN。如果完全离线,把Chart.js下载到本地改路径即可。

4.2 JavaScript读取JSON并画图

app.js里用fetch读取同目录下的predict_result.json,然后构造Chart.js的配置。注意fetch在本地文件协议下可能被浏览器拦截,常见做法是起一个简单HTTP服务,比如python -m http.server 8000

fetch('predict_result.json') .then(response => response.json()) .then(data => { const ctx = document.getElementById('waterChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: data.dates, datasets: [ { label: '实际值', data: data.actual, borderColor: '#2196F3', fill: false }, { label: '预测值', data: data.predicted, borderColor: '#FF5722', borderDash: [5, 5], fill: false } ] }, options: { responsive: true, scales: { y: { beginAtZero: false, title: { display: true, text: '供水量 (m³)' } } } } }); // 填充表格 const tbody = document.querySelector('#dataTable tbody'); data.dates.forEach((date, i) => { const row = `<tr><td>${date}</td><td>${data.actual[i].toFixed(1)}</td><td>${data.predicted[i].toFixed(1)}</td></tr>`; tbody.insertAdjacentHTML('beforeend', row); }); }) .catch(err => console.error('数据加载失败:', err));

borderDash让预测线变成虚线,和实际值区分开。toFixed(1)保留一位小数,避免表格里出现一长串浮点数。insertAdjacentHTMLinnerHTML +=性能好,数据量大时不会反复重绘整个表格。如果控制台报CORS错误,就是文件协议的问题,起HTTP服务即可。

4.3 CSS细节:让图表和表格在手机上也能看

景泰小区的物业人员可能用手机查看,所以加一段媒体查询,小屏时表格字体缩小、图表宽度100%。

@media (max-width: 600px) { .chart-container, table { width: 95%; } th, td { padding: 4px; font-size: 12px; } h2 { font-size: 18px; } }

这段CSS不复杂,但很实用。width: 95%留出边距,font-size: 12px保证表格不溢出。如果表格列多,还可以加overflow-x: auto让表格横向滚动。前端整体思路就是轻量,不引入框架,一个HTML加一个JS文件搞定。

5. 避坑与排查:LSTM水产量预测里最容易翻车的5个地方

5.1 预测曲线整体平移,滞后明显

现象:预测值形状和实际值很像,但总是晚一天,峰值对不上。原因look_back太小,模型看不到足够的周期信息;或者数据没有做差分,趋势项被LSTM当成噪声。解决:把look_back从7调到14,或者对数据做一阶差分后再训练,预测完再累加回去。景泰小区夏季高峰连续多天,14天窗口能覆盖两个完整周周期。

5.2 损失降到很低但预测全是均值

现象:训练loss很小,MAE看着也不错,但画出来预测线几乎是一条水平线。原因:归一化后数据范围被压缩,模型学到“预测均值”就能让MSE很小,这是LSTM在弱周期数据上的常见退化解。解决:改用MAE做损失函数,或者在损失里加对峰值的惩罚权重。另一个办法是增加特征,比如把星期几做one-hot编码加进去,给模型提供额外区分信息。

5.3 前端fetch报错,页面空白

现象:浏览器控制台报Fetch API cannot load file:///...或CORS错误。原因:直接用双击HTML文件的方式打开,浏览器禁止本地文件fetch。解决:在项目目录下运行python -m http.server 8000,然后访问http://localhost:8000。这是最省事的本地服务方式,不需要装nginx。

5.4 反归一化后数值量级不对

现象:预测值在0到1之间,或者变成几万。原因:忘了反归一化,或者scaler用错。解决:检查inverse_transform是否用了训练时的scaler,且输入reshape成(-1,1)。如果预测值几万,说明scaler的data_min_data_max_被测试集污染了,必须重新用训练集fit。

5.5 模型保存后加载预测结果不一致

现象:训练完直接预测正常,保存成h5再加载,预测结果变了。原因:保存时没保存scaler,加载后用了新的scaler或者没归一化。解决:用joblib把scaler一起存下来,加载时先load scaler再transform输入。

import joblib joblib.dump(scaler, 'scaler.pkl') # 加载时 scaler = joblib.load('scaler.pkl')

这个坑很隐蔽,因为模型权重没问题,问题出在预处理。养成“模型和预处理器一起存”的习惯,能省很多排查时间。

6. 进阶技巧:用多步预测和滚动更新让景泰小区模型更实用

单步预测只能看明天,物业更想知道未来7天。多步预测有两种做法:直接多输出和滚动预测。直接多输出是把Dense层改成7个单元,一次输出7天;滚动预测是用预测出的明天当输入,再预测后天。我一般用滚动预测,因为实现简单,且能复用单步模型。

def forecast_next_days(model, last_sequence, scaler, days=7): preds = [] seq = last_sequence.copy() for _ in range(days): pred = model.predict(seq.reshape(1, look_back, 1), verbose=0) preds.append(pred[0, 0]) seq = np.append(seq[1:], pred, axis=0) return scaler.inverse_transform(np.array(preds).reshape(-1, 1)).flatten()

last_sequence是测试集最后7天的归一化数据。每次预测完把结果追加到序列尾部,去掉最老的一天,保持窗口长度不变。这样滚动7次就能得到未来一周的预测。注意滚动预测误差会累积,一般3天以内比较准,7天只能看趋势。

另一个技巧是加“星期特征”。景泰小区周末用水明显低于工作日,把星期几做sin/cos编码加到输入里,能提升5%到10%的精度。

df['dayofweek'] = df['date'].dt.dayofweek df['dow_sin'] = np.sin(2 * np.pi * df['dayofweek'] / 7) df['dow_cos'] = np.cos(2 * np.pi * df['dayofweek'] / 7)

这样特征数从1变成3,input_shape要改成(look_back, 3)。sin/cos编码比one-hot更紧凑,且能表达“周日和周一接近”的周期性。

验证多步预测效果,我习惯用“滚动原点”评估:每次用历史数据预测下一天,然后真实值加入历史,再预测下一天。这样模拟上线后的真实场景,比一次性预测7天更靠谱。

评估方式优点缺点
直接多输出一次出结果,速度快误差不累积但结构固定
滚动预测实现简单,可复用单步模型误差会累积,3天后偏差变大
滚动原点评估最接近真实上线场景计算量大,每次都要重新预测

我现在的习惯是:模型训练完先看单步MAE,再用滚动原点跑一遍测试集,两个指标都达标才往前端推。景泰小区这套跑下来,单步MAE在25左右,滚动7天第7天MAE约45,物业用来做周调度够用了。如果哪天数据量涨到几千条,可以把LSTM换成GRU,参数少一点,训练更快。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 18:15:53

ST-Transformer交通流预测:Python+PyTorch实战指南

简介&#xff1a;本资源是一套面向交通大数据分析与智能交通系统开发者的Python实践项目&#xff0c;聚焦于利用深度学习解决城市交通流短时预测问题。项目基于时空变换网络&#xff08;ST-Transformer&#xff09;架构&#xff0c;融合时空卷积与注意力机制&#xff0c;可有效…

作者头像 李华
网站建设 2026/9/24 18:15:50

Vision-LSTM实战:图像分类新选择与调参避坑指南

简介&#xff1a;这份资源面向希望将Vision-LSTM&#xff08;ViL&#xff09;落地到图像分类任务的深度学习开发者与研究者&#xff0c;提供一套可复现的实战工程。ViL以xLSTM块为核心&#xff0c;每个块包含输入门、遗忘门、输出门与内部记忆单元&#xff0c;并引入指数门控机…

作者头像 李华
网站建设 2026/9/24 18:15:34

DQN交通信号控制实战:解决相位饥饿与绿波失效

简介&#xff1a;本资源是一个基于Python与SUMO仿真的交通信号灯智能调控高分毕设项目&#xff0c;面向计算机、人工智能、自动化及交通工程等专业的本科生与研究生&#xff0c;解决城市交叉口信号配时优化这一典型控制问题。项目采用深度Q网络&#xff08;DQN&#xff09;强化…

作者头像 李华
网站建设 2026/9/24 18:14:47

SSM+Layui+ECharts酒店系统实战:Vo层设计与图表数据对接

简介&#xff1a;这是一套面向JavaWeb初学者与课程设计实践者的酒店管理系统完整项目源码&#xff0c;聚焦预订、入住、退房及客房统计等核心业务场景&#xff0c;助力掌握SSM框架整合开发、前后端协同与数据可视化落地能力。资源共523个文件&#xff0c;涵盖103个Java后端逻辑…

作者头像 李华
网站建设 2026/9/24 18:13:27

真实省域PM2.5时序预测:LSTM全流程实战与避坑指南

简介&#xff1a;本资源是一份面向计算机及相关专业学生的高分期末大作业实战项目&#xff0c;基于Python实现空气质量数据的LSTM时序建模、预测与可视化分析&#xff0c;适用于课程设计、毕业设计及AI项目入门实践。资源包共260个文件&#xff0c;含15个核心Python脚本&#x…

作者头像 李华