☰
农产品价格预测与销量分析系统:基于Django与ECharts的毕设完整实现指南
2026/10/20 2:37:45 网站建设 项目流程

毕业设计年年都在换花样,但“农产品价格预测 + 销量分析 + 可视化”这个组合,始终是经久不衰的热门选题。原因很简单:数据好找,模型能讲出花,界面还能做得很好看,答辩时有展示亮点,文档也好凑字数。我带过的学生里,至少有三四个选了类似的题目,今天就把这道题的完整拆解思路、技术方案和实操细节一次性说清楚,打算做这个方向或者正在纠结怎么动手的同学,可以直接参考。

这个系统说白了就三件事:把历史蔬菜价格和销量数据存进数据库,用算法对未来的价格走势做预测,再把分析结果用图表展示出来。技术栈就是Python + Django + ECharts,以预测算法为核心,以可视化为呈现方式,覆盖数据采集、清洗、建模、预测、展示的完整链路。适合Django刚入门但有Python基础的同学,也适合想快速完成一个拿得出手的毕设、但不想在算法上死磕的实用派。

1. 项目定位与核心功能设计

1.1 毕设选题为什么选农产品价格预测

很多同学选毕设题目时有个误区,觉得题目越“新”越好,搞什么区块链溯源、深度学习病虫害识别,结果做着做着发现数据搞不到、模型跑不动、文档写不出来,最后只能临时换题。农产品价格预测这个方向之所以稳,核心在于它的“技术栈常规但业务逻辑完整”。

先说数据。蔬菜价格和销量数据在各类农业信息平台、批发市场官网都有公开的历史记录,抓取门槛低,字段也比较规整,基本就是日期、品种、最低价、最高价、平均价、交易量这些。数据量不用太大,两三年的日度数据就足够做时间序列分析了。

再说算法。价格预测主流方案无非三类:ARIMA这类传统统计模型、Prophet这类可解释性强的开源工具、LSTM这类深度学习模型。每个方案都能讲出方法论,也都有坑可以写进论文的“问题与展望”里。就算模型效果一般,也可以用“数据量有限”“价格受天气政策等外部因素影响”来解释,这比硬吹效果要真实得多。

最后说展示。可视化是最容易出彩的部分,ECharts画折线图、柱状图、热力图、漏斗图,一套下来页面效果直接拉满。答辩时演示页面比念公式有用得多。

1.2 系统功能模块划分

按照毕设论文的习惯,系统功能一般拆成四个模块来写:

  • 数据管理模块:负责蔬菜品类信息、价格历史数据、销量数据的录入、导入、修改和维护。如果数据是爬来的,这个模块还要承担数据清洗和去重的任务。
  • 价格预测模块:核心模块。用户选择某个蔬菜品种、设定预测天数,系统调用训练好的模型,输出未来N天的价格区间和趋势走向。
  • 销量分析模块:从时间维度分析销量波动规律,包括月度趋势、季度对比、品类排行、同期对比等。
  • 可视化展示模块:用图表把分析结果和预测结果呈现出来,包括价格走势折线图、品类销量柱状图、价格分布热力图、预测区间带图等。

要注意的是,绝大多数毕设的场景都是单机演示,不需要做复杂的权限系统,所以没必要把用户注册登录、角色权限这些做得太重。但至少要有“管理员登录”入口,不然文档里写“系统管理”时没东西可写。我一般建议保留一个简单的登录页面,用来演示会话管理和权限控制,这也算Django的一个基本考点。

1.3 适合什么基础的同学来做

基于Python+Django做这个项目,说实话不需要很高的门槛。

  • Python基础语法要熟,特别是列表推导、字典操作、pandas的DataFrame处理,因为数据处理环节大量用到这些。
  • Django只需要掌握MTV模式、ORM模型、视图函数、模板渲染这四个核心内容。不用去啃中间件、信号、缓存这些进阶知识点,毕设中用到的很少。
  • 机器学习算法不需要从零推导公式,但要能说清楚原理。比如ARIMA为什么需要差分、LSTM为什么能记住长期依赖,这些面试和答辩都会问。
  • 前端只要求会用Bootstrap或简单HTML+CSS搭页面,图表用ECharts直接复制配置改数据就行。

如果你已经能独立写一个Django的图书管理系统,那这个项目的代码量大约在3000到5000行之间,预留三到五周能完成。如果是从零开始边学边做,往后延两周也属正常。

2. 技术选型与系统架构设计

2.1 为什么选了Python+Django而不是Flask

毕设选题里同样有很多人选Flask做后端,但Django在这个场景下优势更明显。

Django自带Admin后台,这个太重要了。数据爬下来之后,你可以先用Admin后台人工检查、修改、补录数据,不需要额外写管理页面。Django的ORM也是现成的,数据库表结构通过模型类自动生成,省去手写SQL的麻烦。还有Django的模板系统,配合Bootstrap和ECharts能很快把页面结构搭出来。

Flask的优势是轻量灵活,适合搞微服务或者接口开发,但对于一个需要完整后台管理、数据展示、论文截图素材的系统来说,Django的“全家桶”特性可以省下大量时间。

版本选择上,Django建议用3.2或4.2 LTS版本,Python用3.8到3.11都行。不建议用最新的Django 5.x,因为部分第三方库的兼容性还不稳定,而且网上多数教程和现成代码都基于老版本,遇到报错排查起来麻烦。

2.2 整体架构:从数据到预测的完整链路

这个系统的数据流可以概括为“采集 → 清洗 → 入库 → 建模 → 预测 → 展示”六步链路。

数据采集环节,用requests加BeautifulSoup去请求公开的农产品价格数据页面并解析HTML表格。如果目标网站有反爬机制,可以加请求头模拟浏览器访问,控制访问频率。不建议用Selenium,太重了,且毕设场景对实时性要求不高,每天更新一次数据就够。

清洗环节放在入库之前。价格字段可能带有“元/公斤”这样的单位,销量字段可能有空值或异常值(比如某天产量为0),日期格式也可能不统一。这些都要用pandas统一处理。经验是写一个独立的clean_data()函数,把清洗逻辑集中在一起,方便文档里截图展示。

入库环节用Django的ORM的bulk_create批量写入,比一条条save快得多。数据库选择上,小体量数据用SQLite就够了,但如果你想体现一下自己的工程能力,换成MySQL也完全可行。我个人的建议是:如果环境里已经装了MySQL就用MySQL,否则直接用SQLite不折腾,反正毕设不会有人拿并发压测来为难你。

建模环节单独拉一个ml_utils.py模块,封装数据读取、训练、预测的函数。这样Django视图里只负责调用,代码结构清爽,也方便写单元测试。

2.3 数据库表结构设计

设计三张核心表就够用了,不建议搞太多关联表给自己增加工作量。

蔬菜品类表存品种名称和分类信息,价格表存每日各品种的批发价格数据,销量表存每日各品种的交易量。

价格表字段设计上要预留灵活性。date存日期,vegetable_id关联品类,price字段存当天平均价,low_price和high_price存最低价和最高价用于后续分析价格波动区间。

销量表相对简单,关联品类和日期,销量字段用FloatField,因为批发市场的交易量经常是小数吨。

我踩过一个坑:一开始把价格和销量放在一张表里,结果有的品种有价格没销量,有的有销量没价格,清洗时头疼得要命。后来拆成两张表,通过品类名称关联,问题就解决了。

2.4 环境准备和项目初始化

环境配置这块,建议直接用Anaconda创建虚拟环境,原因是可以方便地装科学计算库。

conda create -n veggie python=3.9 conda activate veggie pip install django==4.2 pandas numpy statsmodels scikit-learn matplotlib pip install pmdarima # 自动ARIMA调参

如果要用LSTM,还需要装tensorflow或pytorch,但这里要提醒一句:如果你的电脑没有独立显卡,LSTM训练速度会感人。不建议把深度学习作为主模型,可以在论文里作为对比实验提一下,或者用训练好的模型做展示。

项目结构上,我的建议是:

vegetable_project/ ├── manage.py ├── veggie/ # 主项目配置目录 ├── apps/ │ ├── data_manager/ # 数据管理模块 │ ├── forecast/ # 预测模块 │ ├── analysis/ # 销量分析模块 │ └── dashboard/ # 可视化展示模块 ├── data/ # 原始数据存放目录 │ ├── raw/ # 爬取或下载的原始CSV │ ├── processed/ # 清洗后的数据 │ └── models/ # 训练好的模型文件 └── static/ # 静态资源

把Django项目按App拆分而不是全部塞在一个App里,这个习惯在写文档时也能体现“系统模块化设计”的理念,答辩时说不清代码不要紧,架构图一摆就能加分。

3. 核心算法与预测模型实现

3.1 价格预测算法的选型对比

2024年前后毕业设计的预测模型,基本就三种套路,我直接说结论:

ARIMA(差分自回归移动平均模型)是最稳妥的选择。它是统计学经典模型,论文里能写清楚的公式推导逻辑,不需要GPU,训练速度快,样本量只要几百条就能跑出结果。关键是用pmdarima库的auto_arima函数自动寻找最佳参数,避免手工调参的尴尬。

Prophet是另一条好路子。Meta开源的时间序列预测工具,特点是内置了趋势、季节性和节假日效应分解,对农产品价格这种带有明显季节性波动的数据表现不错。缺点是答辩时可能被问“为什么选这个不选别的”,需要提前准备说辞。

LSTM(长短期记忆网络)是看起来最厉害的方案,但也是风险最大的方案。数据量太少根本训不出效果,数据量够的话训练时间又太长,而且超参数调整的坑极多。如果执意要用LSTM,建议只做单一品种的短期预测作为ARIMA的对比实验,不要作为系统主模型。

我的建议:主模型用ARIMA,对比实验用Prophet和LSTM二选一,这样论文里的“模型对比”章节既有内容又不至于翻车。

3.2 ARIMA模型原理与参数确定

ARIMA模型用大白话说就是:通过差分让不平稳的时间序列变平稳,再用自回归项和移动平均项来描述序列的内在规律。公式不用背,但要能理解三个参数的含义。

p是自回归项数,代表当前值与前p个历史值的相关性;d是差分阶数,代表需要做几次差分才能让序列平稳;q是移动平均项数,代表当前值与过去q个预测误差的相关性。

实际项目中直接用pmdarima自动寻优:

from pmdarima import auto_arima model = auto_arima( y=series, start_p=0, max_p=5, start_q=0, max_q=5, d=None, # 自动确定差分阶数 seasonal=True, # 开启季节性 m=7, # 以周为周期 stepwise=True, trace=True )

这里有个关键细节:m参数代表周期长度。农产品价格数据通常以天为粒度,一周内价格波动有明显规律(周末消费需求变化),所以m=7比m=12(月度周期)更合理。auto_arima默认用AIC指标评价模型好坏,AIC越小说明模型在“拟合优度”和“参数简洁度”之间取得平衡。

训练完成后,模型要保存到文件,方便Django视图里直接加载。pmdarima的模型可以用joblib保存:

import joblib joblib.dump(model, 'data/models/arima_cabbage.pkl')

3.3 LSTM模型的实现要点

如果要做LSTM对比实验,代码框架大概是这样的:

import numpy as np from keras.models import Sequential from keras.layers import LSTM, Dense, Dropout from sklearn.preprocessing import MinMaxScaler def build_lstm_model(time_step=30, feature_dim=1): model = Sequential([ LSTM(50, return_sequences=True, input_shape=(time_step, feature_dim)), Dropout(0.2), LSTM(50, return_sequences=False), Dropout(0.2), Dense(1) ]) model.compile(optimizer='adam', loss='mse') return model

time_step代表用过去多少天的数据预测下一天,通常取30到60之间。数据要先用MinMaxScaler做归一化,预测完再反归一化回真实价格。这块如果不做,预测结果会是一堆小得离谱的数字,看起来毫无意义。

训练LSTM的教训是:不要在所有品种上都跑LSTM,选一两个数据最全的品种做演示就够。因为每个品种训练一次至少几分钟,十个品种就得几十分钟,答辩演示时等得尴尬。

3.4 销量分析的维度拆解

销量分析不需要复杂的算法,会用pandas做聚合就行,关键在于分析维度要覆盖到位。

时间趋势分析是最基本的:按月、按季度汇总销量,画折线图看整体走势。这里规律性很强——夏季蔬菜销量普遍偏高,春节前后会有明显的消费高峰。

品类排行分析:按总销量排序,用柱状图展示Top10品种。这个图视觉冲击力强,尤其适合放在论文的“结果分析”章节。

价格相关性分析:调查价格和销量之间的相关性。一般来说叶菜类价格涨了销量会下降,这是需求价格弹性的体现。用pandas的corr函数就能算,再配合散点图展示,妥妥的分析深度。

季节性分解:可以引入statsmodels的seasonal_decompose函数,将销量序列拆成趋势、季节、残差三个部分。这招非常能提升论文的学术感。

4. Django系统实现与可视化集成

4.1 模型层的ORM实现

Django的模型类直接映射数据库表,代码如下:

# apps/data_manager/models.py from django.db import models class VegetableCategory(models.Model): name = models.CharField(max_length=50, unique=True, verbose_name='品种名称') category = models.CharField(max_length=20, verbose_name='分类') created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = 'vegetable_category' verbose_name = '蔬菜品类' class PriceRecord(models.Model): vegetable = models.ForeignKey(VegetableCategory, on_delete=models.CASCADE) date = models.DateField(verbose_name='日期') avg_price = models.FloatField(verbose_name='平均价') low_price = models.FloatField(verbose_name='最低价') high_price = models.FloatField(verbose_name='最高价') class Meta: db_table = 'price_record' unique_together = ('vegetable', 'date') ordering = ['-date']

unique_together这个约束很重要,防止同一品种同一天有重复记录,这也是做数据去重的一个保险机制。

4.2 视图函数的编写思路

Django视图保持“瘦视图”风格,核心判断逻辑放到服务和工具模块里。

价格预测视图的核心逻辑可以拆成几步:

# apps/forecast/views.py import joblib import pandas as pd from django.shortcuts import render from ..data_manager.models import PriceRecord, VegetableCategory def price_forecast(request, veg_id): veg = VegetableCategory.objects.get(id=veg_id) records = PriceRecord.objects.filter(vegetable=veg).order_by('date') df = pd.DataFrame(list(records.values('date', 'avg_price'))) # 填充缺失日期 df['date'] = pd.to_datetime(df['date']) df = df.set_index('date').resample('D').interpolate() model = joblib.load(f'data/models/arima_{veg_id}.pkl') forecast = model.predict(n_periods=7) context = { 'veg_name': veg.name, 'history': df['avg_price'].tolist(), 'forecast': forecast.tolist(), 'dates': [d.strftime('%Y-%m-%d') for d in df.index[-30:].tolist()], 'forecast_dates': [(df.index[-1] + pd.Timedelta(days=i)).strftime('%Y-%m-%d') for i in range(1, 8)] } return render(request, 'forecast.html', context)

这里有个有意思的细节:预测结束后把历史日期和预测日期分别序列化成字符串传给前端,前端拿到后直接渲染成图表的x轴。不要尝试在JavaScript里做日期格式化,跨语言处理日期格式是最容易出乱子的地方。

4.3 ECharts数据可视化集成

可视化是这套系统最容易出效果的部分,方案是直接引入ECharts的CDN,不要自己封装,毕设场景不需要前端工程化。

核心图表类型建议这样分配:

  • 价格走势用折线图,一条线是历史价格,一条线是预测价格,中间用不同颜色区分,这是整个系统的门面图。
  • 销量排名用柱状图,加上从高到低排序,视觉上特别直观。
  • 价格分布用箱线图,展示每个品种的价格分位数分布,能看出哪些蔬菜价格波动大。
  • 销量月历热力图可以不做,但做了绝对加分,ECharts的heatmap组件能展示一年中每天的销量高低,用颜色深浅表示。

ECharts的option配置里有一个关键设置:series类型为line时,data里直接传数值数组就行,但xAxis的data要和yAxis的data长度对应。预测折线图还有一个常见需求,是用带置信区间的面积图展示预测范围。ECharts可以用自定义series实现,但复杂度较高。如果时间紧张,简单一点就是在预测线上下增加两条虚线表示上下界,不做填充。

4.4 数据导入与爬虫实现方案

爬虫部分不建议在正式系统里集成,而是在开发阶段跑一个独立的Python脚本,把数据存成CSV,再通过Django的Admin后台或自定义的导入命令写入数据库。

# data/crawler.py 开发阶段独立脚本 import requests import pandas as pd from bs4 import BeautifulSoup def fetch_price_data(date_str): url = 'https://example.com/data/' params = {'date': date_str} resp = requests.get(url, params=params, headers={ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' }) soup = BeautifulSoup(resp.text, 'html.parser') rows = soup.select('table tr') data = [] for row in rows: cells = row.find_all('td') if len(cells) >= 5: data.append([c.text.strip() for c in cells]) df = pd.DataFrame(data, columns=['品种', '最低价', '最高价', '平均价', '单位']) df.to_csv(f'data/raw/price_{date_str}.csv', index=False)

这样做的好处是爬虫脚本出错不会影响系统稳定,而且论文里可以写“采用独立的离线采集模块,避免对系统实时性造成影响”。

写导入命令时,用Django的manage.py自定义命令:

python manage.py import_data --file data/processed/all_prices.csv

5. 常见问题排查与避坑指南

5.1 遇到的典型问题与解决方案

做一个毕设级别的系统,最怕的不是功能做不完,而是做完了不知道问题出在哪。我把自己带学生时最常见的几个坑列出来,提前避开能省好多时间。

日期格式混乱是最常见的问题。爬下来的数据日期可能是字符串,格式可能是“2024/01/01”“2024-01-01”甚至“2024.01.01”混合出现,直接入库后排序和筛选全乱。解决方法是统一在清洗阶段用pd.to_datetime转换,强制格式化后入库。

模型训练时报错“数据量不足”是另一个高频坑。ARIMA模型虽然处理小样本有优势,但数据量少于100条时预测结果基本不可信。解决方案有两种:一是爬更长时间段的历史数据,二是按品种拆开,只对有充足数据的品种做预测。

Django迁移时报错,通常是数据库里已经有了旧表导致迁移冲突。简单粗暴的方案是:开发阶段不用怕删库,直接把db.sqlite3删掉,重新执行makemigrations和migrate即可。

5.2 ECharts图表显示为空白的排查思路

图表页面打开后只有空白,这个问题几乎每个人都会遇到。排查顺序有讲究:

  • 先确认数据是否传到前端。在JavaScript里加一行console.log(option)输出配置对象,看数据数组是不是空的。
  • 再确认ECharts库是否加载成功。打开浏览器开发者工具,Network里查找echarts.min.js是否加载到。如果没有,多半是static资源配置路径出了问题。
  • 检查容器高度。ECharts的图表容器必须有明确的height,不能依赖内部内容撑开,很多空白问题就是因为div高度为0。

5.3 预测效果不理想的优化策略

如果你用ARIMA跑出来预测结果是一条几乎水平的直线,别慌,这很常见。原因通常是原始数据已经够平稳,模型学到的信息量少,预测自然趋向均值。优化手段有三个层级:

  • 基础优化:增加数据维度,把节假日、天气因素作为外生变量传入。ARIMA可以扩展成ARIMAX,pmdarima支持xreg参数,把星期几、是否节假日、当月气温作为额外输入。
  • 进阶优化:换Prophet模型,它的趋势和季节分解能力更强,适合明显受季节影响的品种。
  • 终极优化:用集成策略,对每个品种分别跑ARIMA和Prophet,再取平均值作为最终预测。这种操作写到论文里就是“基于多模型融合的预测方法”,听起来高级,实现起来也不难。

5.4 毕业论文写作与答辩准备要点

文档和程序在毕设中同样重要,甚至可以说文档占一半分数。

论文结构建议按七章来写:绪论、相关技术介绍、系统需求分析、系统设计、系统实现、系统测试、总结与展望。

绪论里写研究背景和意义时,建议从“农产品价格波动影响民生”和“大数据技术助力农业决策”两个角度切入,不要自己编造调研数据,引用公开报道和学术论文的表述即可。

系统测试部分容易被忽视,但这块是凑字数和增加可信度的神器。至少要包含功能测试用例表(30条以上)、性能测试(页面响应时间)、兼容性测试(Chrome和Edge),每一项都要保证真实跑过并截图保存。

答辩时的必问题目基本就那么几个:为什么选这个题目、数据从哪来、模型效果怎么样、预测和实际差距大怎么办。前两个靠熟悉项目就能答,后两个要准备话术。模型效果差就解释数据量和外部扰动因素;预测和实际有差距就解释模型是参考工具,不构成生产决策依据,生产场景下会结合人工经验修正。这些说法技术含量不高,但态度正确,老师们普遍认可。

6. 后期扩展与真实项目经验

6.1 系统上线部署时的注意事项

毕设系统虽然主要是单机演示,但总有同学想放到服务器上跑,或者录演示视频时想让运行环境看起来更像样。真正部署时容易踩两个坑:静态文件和数据库迁移。

Django生产模式下不再帮你处理静态文件,需要在settings.py里设置STATIC_ROOT,然后执行python manage.py collectstatic把静态文件收集到统一目录。用Nginx服务静态文件是常规做法,但如果图省事,用Django自带的runserver部署到服务器上做演示也行,只是不要对外声称是生产环境。

SQLite数据库在服务器上有时会碰到文件锁问题。如果并发访问量稍微大一点,SQLite会报database is locked错误。解决方案很简单:生产演示时换成MySQL或PostgreSQL。Django的ORM模型不用改,只要在settings.py里修改数据库配置即可。

6.2 如何在这个基础上加自己的创新点

现在毕设查重和导师审查越来越严格,纯粹的“老三样”确实不容易拿高分。想加创新点,可以从这些方向上做文章。

做更细粒度的预测。把“按品种预测”提升到“按产区预测”或“按规格等级预测”。同一品种不同产地的价格差异很大,能体现数据挖掘深度。

引入天气数据做融合分析。申请使用公开的天气API,把温度、降水量作为特征加入预测模型。这个方向在论文里很讨巧——农业本身就是老天爷赏饭吃的行业,天气和价格相关性容易解释。

增加可视化地图组件。用ECharts的地图模式,把不同省份的蔬菜价格填充到地图上形成热力地图。这个视觉效果好,代码工作量也不大,适合计划在演示环节加分的人。

开发移动端适配。如果前端用Bootstrap,自适应效果是天然支持的,做一套响应式页面放进论文里,能证明你考虑了多端应用场景。

6.3 我操作下来最真实的体会

这个项目带完一轮下来,我最想说的是:别把预测算法看得太重,也别把可视化看得太轻。

很多同学做这个题目的误区是花三周调模型,想要预测精度达到95%以上,这是不可能的。价格预测本质上充满不确定性,学术界的论文也只能做到趋势预测,追求绝对精度是和自己过不去。做得差不多,能画出合理的趋势线,能解释清楚模型原理,这就够了。

相反,可视化是大多数同学轻视的部分。其实答辩现场,老师盯着屏幕的时间大多是在看页面效果,而论文里的模型公式和算法流程,翻两页就跳过了。把图表配色调整好,把页面排版做干净,把交互操作捋顺,这部分的投入产出比远高于死磕模型精度。

还有一句掏心窝的话:做毕设的过程一定要留好阶段记录。每周把做了什么、遇到什么问题、怎么解决的记在开发日志里,写论文的时候会发现这些笔记就是最好的素材,比最后对着代码硬憋字数轻松十倍。代码结构也要注意可读性,函数命名规范一点,每个功能模块的注释写清楚,这些都是论文附录的直接来源,也是答辩时能从容回应的底气所在。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询