农产品销售数据分析一直是农业产业链中的关键环节,但传统的数据处理方式往往面临几个痛点:数据分散在各个销售渠道难以整合、分析维度单一、结果呈现不够直观。我在实际农业项目中经常遇到这样的场景:合作社负责人拿着一堆Excel表格,却无法快速判断哪些农产品在哪些地区更受欢迎,价格波动对销量有多大影响。
这个基于Python+Django+Echarts的农产品销售分析系统,正是为了解决这些实际问题而设计的。它能够:
特别说明:虽然标题提到Hadoop/Spark,但从项目实际架构看,当前版本更适合中小规模数据场景。如果数据量达到TB级,才需要考虑引入分布式计算框架,这点在技术选型部分会详细解释。
系统采用经典的B/S三层架构:
code复制前端展示层:HTML + Echarts + Bootstrap
业务逻辑层:Django (Python 3.8+)
数据存储层:MySQL 8.0
选择这套技术栈主要基于以下考量:
典型的数据处理流程如下:
数据采集:
数据清洗:
python复制# 示例:价格数据清洗
def clean_price(data):
try:
price = float(data['price'])
if price <= 0:
return None
return round(price, 2)
except:
return None
分析计算:
可视化渲染:
javascript复制// Echarts地图配置示例
option = {
tooltip: {
trigger: 'item',
formatter: '{b}<br/>销量: {c} (吨)'
},
visualMap: {
min: 0,
max: 1000,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['#e0f3f8', '#abd9e9', '#74add1', '#4575b4', '#313695']
}
}
}
这是农产品决策中最关键的维度之一。我们采用散点图+趋势线的方式呈现:
数据准备:
python复制from scipy import stats
df = pd.DataFrame(list(SalesData.objects.all().values()))
slope, intercept, r_value, p_value, std_err = stats.linregress(df['price'], df['quantity'])
前端渲染:
javascript复制series: [{
type: 'scatter',
data: dataPoints,
symbolSize: function (data) {
return Math.sqrt(data[1]) * 2;
}
}, {
type: 'line',
showSymbol: false,
data: [[minPrice, intercept + slope*minPrice], [maxPrice, intercept + slope*maxPrice]]
}]
实战经验:农产品价格敏感度分析要注意剔除促销期数据,否则会扭曲正常的价格弹性系数。我们曾遇到某蔬菜因促销导致分析失真,后来通过添加"is_promotion"字段解决了这个问题。
中国地图展示是农产品分析的特色需求,实现要点:
地理编码处理:
性能优化:
python复制# 使用values()+annotate()替代遍历查询
region_data = SalesData.objects.values('province').annotate(
total_quantity=Sum('quantity'),
avg_price=Avg('price')
).order_by('-total_quantity')
交互增强:
javascript复制myChart.on('click', function (params) {
if(params.componentType === 'series') {
window.open('/detail/?province=' + encodeURIComponent(params.name));
}
});
当销售记录超过100万条时,会遇到性能瓶颈。我们通过以下方案解决:
数据库优化:
CREATE INDEX idx_product_region ON sales_data (product_id, province)select_related减少查询次数缓存策略:
python复制from django.core.cache import cache
def get_sales_trend():
key = 'sales_trend_2023'
data = cache.get(key)
if not data:
data = heavy_calculation()
cache.set(key, data, 3600) # 1小时缓存
return data
异步处理:
python复制# 使用Celery处理耗时任务
@app.task
def generate_yearly_report(year):
# 生成年度报告PDF
return pdf_path
动态数据加载:
javascript复制function loadProvinceData(province) {
$.get('/api/sales/by-province/', {province: province}, function(data) {
myChart.setOption({
series: [{
data: data
}]
});
});
}
移动端适配:
css复制@media (max-width: 768px) {
.chart-container {
width: 100%;
height: 300px;
}
}
推荐使用Docker Compose部署:
dockerfile复制# docker-compose.yml
version: '3'
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: yourpassword
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db
关键指标监控:
日志分析:
python复制LOGGING = {
'handlers': {
'file': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler',
'filename': 'logs/django.log',
'maxBytes': 1024*1024*5, # 5MB
'backupCount': 5,
},
}
}
根据实际使用反馈,下一步可以重点优化:
预测功能增强:
移动端体验:
分布式扩展:
python复制# 当单机无法处理时,可以考虑Spark集成
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("SalesAnalysis").getOrCreate()
df = spark.read.csv("hdfs://sales_data.csv")
这个项目最让我有成就感的,是看到完全不懂技术的农户也能通过颜色深浅快速理解哪些地区卖得好。技术真正的价值,就是让复杂的信息变得人人可理解。