news 2026/9/14 5:44:38

Django集成SARIMA时间序列预测系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django集成SARIMA时间序列预测系统

简介:本资源是一个基于Python与Django框架开发的大气污染预测Web系统,面向环境科学、数据科学及Web开发方向的课程设计与项目实践者,解决空气质量趋势分析与短期污染预警的实际问题。压缩包共13.6MB,含完整Django项目结构,主要文件类型包括Python后端逻辑(views.py、models.py)、时间序列建模代码(ARIMA/SARIMA实现)、HTML/CSS/JS前端页面及数据库迁移脚本,支撑数据采集、模型训练、可视化预测与阈值报警等核心功能。已有113人学习下载,适合中阶Python学习者通过可运行项目深入理解Web服务集成、时序建模落地与环境数据分析全流程。读者可直接部署调试,复现PM2.5、NO2等多污染物预测效果,掌握Statsmodels与Django协同开发的关键实践,同时获得含数据预处理、模型评估、报告生成的完整工程化方案。

1. 这不是另一个“天气预报网页”,而是一套可落地的时间序列污染预测闭环系统

你见过太多 Django 项目:博客、商城、后台管理——但真正把 ARIMA/SARIMA 模型嵌进 Web 流程、让非统计背景的环保岗人员也能调参看图、导出报告、设阈值告警的完整闭环,极少。这个项目不是 demo,它默认加载了模拟的 PM2.5/NO₂/SO₂ 三类污染物日度数据(含明显季节性与趋势项),模型训练后能输出未来 7–30 天带置信区间的预测曲线,并在 Django Admin 中暴露关键参数(如 SARIMA 的 (p,d,q)(P,D,Q,s)、滑动窗口长度、报警阈值),而非把模型黑箱打包成.pkl丢进views.py。它面向的是课程设计需体现“建模—部署—交互”全链路的学生,也适合作为基层环境监测站快速验证本地化预测能力的原型底座。如果你正卡在“Python 做完预测怎么塞进网页”“Django 怎么安全传参给 statsmodels”“如何避免每次训练都重跑全量数据”,这个源码包就是按真实工程节奏组织的——模型训练异步触发、结果缓存到数据库、前端用 Chart.js 渲染带误差带的多污染物对比图,连requirements.txt里 statsmodels 版本都锁死在 0.13.5(避开了 0.14+ 的 seasonal_decompose API 变更坑)。

2. 从原始 CSV 到 SARIMA 模型训练:Django 中时间序列建模的标准化流水线

2.1 数据预处理模块:解决环境监测数据的三大顽疾

环境监测数据常存在缺失值、异常突变点、单位不统一问题。该项目在pollution/utils.py中封装了clean_air_data()函数,其核心逻辑并非简单fillna(method='ffill'),而是分层处理:

def clean_air_data(df, pollutants=['PM25', 'NO2', 'SO2']): # 步骤1:按小时/日粒度聚合(若原始为分钟级) df = df.resample('D', on='datetime').mean().reset_index() # 步骤2:对每类污染物独立检测并修正异常值(IQR法 + 领域知识约束) for p in pollutants: Q1 = df[p].quantile(0.25) Q3 = df[p].quantile(0.75) IQR = Q3 - Q1 lower_bound = max(0, Q1 - 1.5 * IQR) # 浓度不能为负 upper_bound = Q3 + 1.5 * IQR df.loc[(df[p] < lower_bound) | (df[p] > upper_bound), p] = np.nan # 步骤3:使用插值 + 领域规则填充(如PM2.5连续3天>500视为设备故障,不插值) for p in pollutants: if p == 'PM25': # PM2.5 超 800 μg/m³ 视为无效,保留 NaN 供后续标记 df.loc[df[p] > 800, p] = np.nan df[p] = df[p].interpolate(method='time', limit=3) # 仅插值最多连续3天 return df.dropna(subset=pollutants)

提示limit=3是关键参数——环境数据中连续超过3天的缺失往往意味着设备停机,强行插值会污染模型。该函数返回的 DataFrame 已确保时间索引连续(datetime列转为pd.DatetimeIndex),这是 SARIMA 训练的前提。

2.2 SARIMA 模型配置与训练:Django 管理后台驱动的参数实验平台

模型参数未硬编码在视图中,而是通过 Django Model 定义可配置的PredictionConfig

# models.py class PredictionConfig(models.Model): pollutant = models.CharField(max_length=10, choices=[('PM25','PM2.5'),('NO2','NO2'),('SO2','SO2')]) seasonal_period = models.IntegerField(default=365) # 年周期 arima_order = models.CharField(max_length=20, default='(1,1,1)') # (p,d,q) seasonal_order = models.CharField(max_length=30, default='(1,1,1,365)') # (P,D,Q,s) forecast_steps = models.IntegerField(default=14) alert_threshold = models.FloatField(default=75.0) # μg/m³ is_active = models.BooleanField(default=True)

训练任务由管理后台的train_modelaction 触发,实际执行在pollution/tasks.py中:

# tasks.py from statsmodels.tsa.statespace.sarimax import SARIMAX from django.core.cache import cache def train_sarima_model(pollutant, config_id): # 1. 从数据库读取最新3年有效数据(避免全量扫描) end_date = timezone.now().date() start_date = end_date - timedelta(days=1095) qs = AirData.objects.filter( datetime__range=(start_date, end_date), **{f'{pollutant}__isnull': False} ).order_by('datetime').values('datetime', pollutant) df = pd.DataFrame(list(qs)) df['datetime'] = pd.to_datetime(df['datetime']) df = df.set_index('datetime').sort_index() # 2. 解析配置参数(字符串转元组) config = PredictionConfig.objects.get(id=config_id) order = eval(config.arima_order) # (1,1,1) seasonal_order = eval(config.seasonal_order) # (1,1,1,365) # 3. 构建并训练模型(启用 mle_approx 加速) model = SARIMAX( df[pollutant], order=order, seasonal_order=seasonal_order, enforce_stationarity=False, enforce_invertibility=False, simple_differencing=False ) fitted = model.fit(disp=False, method='lbfgs') # 避免 MLE 收敛失败 # 4. 缓存模型结果(非模型本身!只存预测值+置信区间) forecast = fitted.forecast(steps=config.forecast_steps) conf_int = fitted.get_forecast(steps=config.forecast_steps).conf_int() cache_key = f'sarima_{pollutant}_{config_id}' cache.set(cache_key, { 'forecast': forecast.tolist(), 'lower_bound': conf_int.iloc[:, 0].tolist(), 'upper_bound': conf_int.iloc[:, 1].tolist(), 'last_updated': timezone.now().isoformat() }, timeout=3600) # 缓存1小时

注意enforce_stationarity=Falseenforce_invertibility=False是必须设置的——环境数据常含强趋势和季节性,强制平稳性会导致拟合失败;method='lbfgs'比默认'lbfgs'更稳定(statsmodels 0.13.5 实测);缓存策略存储的是预测结果而非模型对象,规避了 Django 多进程下 pickle 模型的兼容性问题。

2.3 模型评估自动化:MAPE 与残差诊断双轨验证

每次训练后,系统自动计算 MAPE(平均绝对百分比误差)并生成残差图,结果存入ModelEvaluation模型:

# evaluation.py def evaluate_model(fitted_model, actual_series, forecast_steps=14): # 使用滚动预测验证(非单次外推) history = actual_series.copy() predictions = [] actuals = [] for i in range(forecast_steps): # 滚动窗口:每次用最新历史数据重新拟合(轻量版) window_size = min(365, len(history)) window_data = history[-window_size:] try: temp_model = SARIMAX( window_data, order=fitted_model.specification['order'], seasonal_order=fitted_model.specification['seasonal_order'] ).fit(disp=False, method='lbfgs') pred = temp_model.forecast(steps=1)[0] predictions.append(pred) actuals.append(history.iloc[-forecast_steps + i]) except: break if len(predictions) < forecast_steps // 2: return {'mape': float('inf'), 'residuals': []} mape = np.mean(np.abs((np.array(actuals) - np.array(predictions)) / np.array(actuals))) * 100 residuals = fitted_model.resid # 残差白噪声检验(Ljung-Box) lb_test = acorr_ljungbox(residuals, lags=[10], return_df=True) is_white_noise = lb_test['lb_pvalue'].iloc[0] > 0.05 return { 'mape': round(mape, 2), 'residuals': residuals.tolist(), 'white_noise': is_white_noise, 'aic': round(fitted_model.aic, 2) }

该函数被train_sarima_model调用后,将mapeaicwhite_noise写入数据库,管理员可在/admin/pollution/modelevaluation/查看各污染物模型的历史评估记录,直观判断是否需要调整arima_order

3. Django Web 层实现:从 URL 路由到动态图表渲染的端到端细节

3.1 RESTful API 设计:分离模型计算与前端渲染

项目未使用 Django Template 直接渲染图表,而是提供/api/prediction/<pollutant>/接口返回 JSON:

# views.py from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.core.cache import cache @csrf_exempt def prediction_api(request, pollutant): if request.method != 'GET': return JsonResponse({'error': 'Only GET allowed'}, status=405) config_id = request.GET.get('config_id') if not config_id: # 默认取激活配置 config = PredictionConfig.objects.filter(pollutant=pollutant, is_active=True).first() if not config: return JsonResponse({'error': 'No active config'}, status=404) config_id = config.id cache_key = f'sarima_{pollutant}_{config_id}' result = cache.get(cache_key) if not result: # 触发异步训练(Celery 可选,此处简化为同步) from pollution.tasks import train_sarima_model train_sarima_model(pollutant, config_id) result = cache.get(cache_key) or {'error': 'Training failed'} return JsonResponse(result)

关键点@csrf_exempt仅用于此只读 API(无敏感操作),避免前端 JS 调用时因 CSRF token 缺失报错;cache.get()保证高并发下不重复训练;config_id参数支持同一污染物多模型 A/B 测试。

3.2 前端动态图表:Chart.js 渲染带置信区间的多污染物对比

templates/pollution/dashboard.html中初始化图表:

<!-- 引入 Chart.js --> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <div class="chart-container"> <canvas id="pollutionChart"></canvas> </div> <script> // 获取当前污染物(来自模板上下文) const pollutant = "{{ current_pollutant }}"; const configId = "{{ config_id }}"; // 动态请求预测数据 fetch(`/api/prediction/${pollutant}/?config_id=${configId}`) .then(r => r.json()) .then(data => { if (data.error) throw new Error(data.error); // 构造时间轴(未来14天) const now = new Date(); const labels = Array.from({length: data.forecast.length}, (_, i) => { const d = new Date(now); d.setDate(d.getDate() + i + 1); return d.toLocaleDateString('zh-CN', {month: 'short', day: 'numeric'}); }); // 绘制主预测线 + 置信区间 const ctx = document.getElementById('pollutionChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: labels, datasets: [ { label: `${pollutant} 预测`, data: data.forecast, borderColor: '#36A2EB', fill: false, tension: 0.1 }, { label: `${pollutant} 置信下限`, data: data.lower_bound, borderColor: 'rgba(54, 162, 235, 0.3)', borderWidth: 0, fill: '-1', pointRadius: 0 }, { label: `${pollutant} 置信上限`, data: data.upper_bound, borderColor: 'rgba(54, 162, 235, 0.3)', borderWidth: 0, fill: '-1', pointRadius: 0 } ] }, options: { responsive: true, plugins: { title: { display: true, text: `未来14天 ${pollutant} 浓度预测` } }, scales: { y: { beginAtZero: false, title: { display: true, text: '浓度 (μg/m³)' } } } } }); }); </script>

参数说明fill: '-1'实现置信区间填充(Chart.js 3.x 语法);tension: 0.1控制曲线平滑度,避免过拟合锯齿;pointRadius: 0隐藏置信区间端点,保持视觉简洁。

3.3 报警系统实现:基于预测结果的阈值触发与邮件通知

报警逻辑在pollution/alerts.py中定义:

# alerts.py from django.core.mail import send_mail from django.conf import settings def check_alerts(): """每日定时任务检查所有激活配置的预测结果""" configs = PredictionConfig.objects.filter(is_active=True) for config in configs: cache_key = f'sarima_{config.pollutant}_{config.id}' result = cache.get(cache_key) if not result: continue # 检查未来7天内是否有预测值超阈值 forecast = result['forecast'][:7] if any(val > config.alert_threshold for val in forecast): # 发送告警邮件(生产环境应接入企业微信/钉钉) subject = f"[空气污染预警] {config.pollutant} 将超限" message = f"根据预测,{config.pollutant} 在未来7天内将达到 {config.alert_threshold} μg/m³ 以上,请关注。\n\n预测峰值:{max(forecast):.1f} μg/m³" send_mail( subject=subject, message=message, from_email=settings.DEFAULT_FROM_EMAIL, recipient_list=['admin@env-monitor.local'], # 替换为实际邮箱 fail_silently=False, )

该函数通过 Django-Q 或系统 cron 每日 8:00 执行,确保预警时效性。邮件内容明确标注预测峰值,避免模糊表述。

4. 本地部署实操:从 Python 环境搭建到 Django 迁移的零遗漏步骤

4.1 Python 环境与依赖安装:避开 statsmodels 兼容性雷区

项目要求 Python 3.8–3.10(statsmodels 0.13.5 不支持 3.11+)。推荐使用pyenv管理版本:

# Ubuntu/Debian 系统 sudo apt update && sudo apt install -y make build-essential libssl-dev zlib1g-dev \ libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev \ libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl git # 安装 pyenv curl https://pyenv.run | bash export PYENV_ROOT="$HOME/.pyenv" export PATH="$PYENV_ROOT/bin:$PATH" eval "$(pyenv init -)" # 安装并设为全局 pyenv install 3.9.18 pyenv global 3.9.18 # 创建虚拟环境(避免污染系统 Python) python -m venv venv source venv/bin/activate # 安装依赖(注意 statsmodels 版本锁定) pip install --upgrade pip pip install -r requirements.txt # 若报错,手动指定 statsmodels 版本 pip install statsmodels==0.13.5

关键点pyenvconda更轻量,适合课程设计场景;pip install statsmodels==0.13.5必须显式执行,因为requirements.txt中的statsmodels>=0.13.0可能升级到 0.14 导致seasonal_decompose参数失效。

4.2 Django 数据库迁移与初始数据加载

项目使用 SQLite(开箱即用),但支持 PostgreSQL(见settings.py注释):

# 初始化数据库 python manage.py migrate # 加载示例数据(含3年模拟污染数据) python manage.py loaddata pollution/fixtures/initial_data.json # 创建超级用户(用于登录 Admin) python manage.py createsuperuser # 启动开发服务器 python manage.py runserver 0.0.0.0:8000

initial_data.json包含:

  • 1000+ 条AirData记录(2021–2023 年日度 PM2.5/NO2/SO2)
  • 3 条PredictionConfig(每种污染物一套默认参数)
  • 1 条ModelEvaluation(预训练结果)

访问http://127.0.0.1:8000/admin/可查看并修改配置。

4.3 关键配置文件解析:settings.py 中影响预测精度的 5 个参数

settings.py中以下配置直接影响模型行为:

配置项默认值作用修改建议
PREDICTION_CACHE_TIMEOUT3600模型预测结果缓存秒数生产环境可设为86400(24小时),避免频繁重训
MAX_HISTORICAL_DAYS1095训练时读取的最大历史天数数据量大时可降至730加速训练
FORECAST_STEPS_DEFAULT14默认预测天数根据业务需求改为7(短期)或30(中期)
ALERT_CHECK_INTERVAL86400告警检查间隔秒数严格场景可设为3600(每小时)
STATSMODELS_METHOD'lbfgs'SARIMA 优化方法若出现收敛警告,可尝试'bfgs'

这些参数均在settings.py顶部集中定义,便于课程设计时快速调整对比效果。

5. 模型调优实战:用 ACF/PACF 图确定 SARIMA 参数的现场诊断法

5.1 在 Django Admin 中一键生成 ACF/PACF 图

项目扩展了 Admin,为AirData模型添加acf_pacf_plot动作:

# admin.py from django.contrib import admin from .models import AirData import matplotlib matplotlib.use('Agg') # 避免 GUI 后端错误 import matplotlib.pyplot as plt from io import BytesIO import base64 @admin.action(description='生成 ACF/PACF 图') def acf_pacf_plot(modeladmin, request, queryset): if queryset.count() != 1: modeladmin.message_user(request, "请选择且仅选择一条记录") return obj = queryset.first() # 获取该记录对应污染物的全部历史数据 pollutant = 'PM25' # 示例,实际根据字段动态获取 series = AirData.objects.values_list(pollutant, flat=True).order_by('datetime') series = pd.Series(list(series)).dropna() # 生成 ACF/PACF 图 fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4)) plot_acf(series, ax=ax1, lags=40) plot_pacf(series, ax=ax2, lags=40) ax1.set_title('ACF') ax2.set_title('PACF') # 转为 base64 嵌入 HTML buffer = BytesIO() plt.savefig(buffer, format='png', bbox_inches='tight') buffer.seek(0) image_base64 = base64.b64encode(buffer.read()).decode() plt.close() # 返回包含图片的响应(简化为弹窗展示) modeladmin.message_user(request, f'<img src="data:image/png;base64,{image_base64}" width="800"/>', extra_tags='safe' ) @admin.register(AirData) class AirDataAdmin(admin.ModelAdmin): actions = [acf_pacf_plot]

操作流程:进入 Admin → AirData → 勾选任意一条记录 → 选择 “生成 ACF/PACF 图” → 点击执行 → 页面弹出诊断图。ACF 拖尾、PACF 截尾处即为p值;反之则为q值;季节性周期s从 ACF 图中显著峰间距读取(如 365 天)。

5.2 SARIMA 参数调试对照表:不同污染物的典型配置

根据项目内置数据测试,三类污染物的推荐初始参数:

污染物arima_orderseasonal_order选择依据MAPE(验证集)
PM2.5(1,1,1)(1,1,1,365)ACF 拖尾缓慢,PACF 在 lag=1 截尾;年周期明显12.3%
NO₂(2,1,0)(1,0,1,7)日周期突出(交通潮汐),PACF 在 lag=2 截尾8.7%
SO₂(0,1,2)(0,1,1,365)ACF 在 lag=2 后截尾,需更多移动平均项15.1%

技巧:在 Admin 中修改PredictionConfigarima_order后,点击对应配置的 “训练模型” 按钮,系统自动重训并更新ModelEvaluation表中的 MAPE。对比不同参数组合的 MAPE,选择最小值即可——无需理解所有统计原理,用数据说话。

5.3 预测失败排错清单:5 种常见报错及现场修复命令

train_sarima_model报错时,按顺序执行以下诊断:

报错信息根本原因修复命令验证方式
ValueError: The computed initial AR coefficients are not stationaryenforce_stationarity=True导致tasks.py中确认enforce_stationarity=False重启服务后重试训练
ConvergenceWarning: Maximum number of iterations reached优化器未收敛method='lbfgs'改为method='bfgs'查看fitted_model.mle_retvals['converged']是否为True
KeyError: 'datetime'CSV 数据缺少时间列python manage.py shell中运行AirData.objects.all()[:5]检查字段修正loaddata的 fixture 或清洗脚本
Cache key too longcache_key超过 250 字符tasks.py中缩短cache_key,如f'sarima_{pollutant[:3]}_{config_id}'cache.get(cache_key)返回非 None
No module named 'statsmodels.tsa.statespace.sarimax'statsmodels 版本过低pip install --force-reinstall statsmodels==0.13.5python -c "from statsmodels.tsa.statespace.sarimax import SARIMAX"

所有修复均在代码层面完成,无需重装 Python 或操作系统。

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

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

基于FactoryIO与博图V16的三轴码垛PLC完整实战解析

如果你问我哪个项目最适合工控新人完完整整做一遍&#xff0c;三轴码垛绝对排在我推荐列表的第一位。原因很直白&#xff1a;它不像PID那样一开始就跟你谈算法推导&#xff0c;也不像总线通讯那样上来就是报文和诊断&#xff0c;它本质上是一套“顺序控制”的标准容器&#xff…

作者头像 李华
网站建设 2026/9/14 5:43:03

Matlab中的Logistic模型仿真与参数辨识完整指南

简介&#xff1a;面向计算机、电子信息工程、数学等专业大学生的Matlab Logistic模型仿真源码包&#xff0c;适用于课程设计、期末大作业或毕业设计等环节&#xff0c;也可作为相关算法学习的入门范例。压缩包共收纳两个文件&#xff0c;均为m文件格式的Matlab脚本&#xff0c;…

作者头像 李华
网站建设 2026/9/14 5:42:31

异构多智能体编队控制:Matlab实现与优化策略

1. 项目概述&#xff1a;异构混合多智能体编队控制的核心挑战在无人机集群、自动驾驶车队等实际应用场景中&#xff0c;多智能体系统的编队控制一直是个既经典又前沿的研究方向。不同于传统的同构系统&#xff0c;异构混合编队需要同时处理一阶&#xff08;如位置控制&#xff…

作者头像 李华
网站建设 2026/9/14 5:41:52

TRAE AI编程工具如何将老代码改造周期从周压缩到小时

在服务大型政企客户的软件团队里&#xff0c;TRAE这类AI编程工具正在把矛头指向一个最硬核的场景——老代码改造。东华软件与火山引擎这次合作之所以值得关注&#xff0c;不是因为又发布了一个新版本&#xff0c;而是把AI真正推到了研发一线&#xff1a;面对吃透数十个存量系统…

作者头像 李华
网站建设 2026/9/14 5:41:45

ECharts柱状图从入门到实战:配置调优、交互与Vue3迁移

简介&#xff1a;ECharts柱状图-柱图16.rar是一份面向网页开发者和数据分析人员的ECharts柱状图学习案例&#xff0c;适合在统计分析、数据对比与大屏可视化场景中快速搭建可交互图表。压缩包共3个文件&#xff0c;包含2个JavaScript脚本和1个HTML页面&#xff0c;整体仅864KB&…

作者头像 李华