matplotlib学习 -- 时令蔬菜水果农产品挖掘


挖掘思路:时令蔬菜有哪些?针对国内农产品批发价的时间序列分析

时令挖掘

借鉴上述链接的挖掘思路,练习matplotlib库

摘要¶

又到了吃西瓜的季节。之所以在夏季吃西瓜,不仅仅因为其可以解暑,而且在夏天是西瓜的大量上市时期,价格还会比较便宜。在我们的食谱中,还有许多像西瓜这样的具有明显季节性的食材。这次的项目将通过分析农产品批发价的时间序列数据,发现具有强季节性的蔬菜,为在合适的季节吃合适的蔬菜提供参考。同时也对过去几年农产品的价格变化趋势进行了解。其中的主要发现包括:
价格具有强季节性的农产品主要是蔬菜和水果。例如菠菜、韭菜在春季,西瓜、冬瓜在夏季,巨峰葡萄在秋季,莲藕在冬季的价格会较低。
在过去两年里,约52%的农产品有明显的价格变化趋势。其中大部分为价格上升趋势,以水产品为代表。而猪肉和生姜是少有的有着价格下降趋势的产品。
不过,价格变化不仅受到农产品供给变化的影响,还会受到市场需求、运输存储、制度政策等变化的影响。因此如果要确认是否真的是时令蔬菜,还应结合农产品的实际培育周期来进行校验。

数据说明

数据来自中国农业农村部在过去两年(2020年6月到2022年5月)从全国批发市场采集的逐月农产品批发价格数据。数据中涉及到的农产品品种包含5种畜禽产品、5种水果、7种水产品以及28种蔬菜。

数据预处理


improt pandas as pd

# 画图
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as ticker
from pylab import mpl

# 数据one_hot 处理
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder

mpl.rcParams['font.sans-serif'] = ['Source Han Serif SC'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题

# 文件来自于挖掘思路的数据文件
df = pd.read_csv("wholesale_price_of_agricultural_products.csv")

#df.head(1)
#year_month	product	price	category
#0	202012	芹菜	3.76	蔬菜

# 日期转换
df['ds'] = pd.to_datetime(df['year_month'])
# 月份
df['mon'] = df['ds'].dt.month
# 年
df['year'] = df['ds'].dt.year


# 月份进行one_hot编码
enc = OneHotEncoder(sparse=False)
result = enc.fit_transform(df[['mon']]) 

pd_mon = pd.DataFrame(result)
df_all = pd.concat([df, pd_mon], axis=1)
#df_all.head(1)
#year_month	product	price	category	ds	mon	year	mon1	mon2	mon3	mon4	mon5	mon6	mon7	mon8	mon9	mon10	mon11	mon12	
#202012	芹菜	3.76	蔬菜	2020-12-01	12	2020	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	0.0	1.0	

各类农产品批发价的历史变化

col = ['category', 'product']
df_group = df_all.groupby(col)

import numpy as np
import matplotlib.pyplot as plt

# 画出产品历史价格变化图
for k, v in df_group:

    v = v.sort_values(by=['year', 'mon']).reset_index(drop=True)
   
    ax = plt.figure(figsize=(20, 10)).add_subplot(111)
    plt.xticks(rotation='90')
    plt.xlabel("Mon")
    plt.ylabel("Price")
    plt.margins(0, 0)
    
    title = k[0] + "_" + k[1]
	
	# 图标题
    plt.title(title, fontdict={'fontsize':20})
	
	# 横坐标 - 纵坐标
    x = [str(v.iloc[i]['year']) + "_" + str(v.iloc[i]['mon']) for i in range(len(v))]
    y = v['price']
	
	# 绘制折线图
    ax.plot(x, y,'bo-',color = 'b', label='m_price')
	
	# 使用axvspan 填充背景
	# 红-春 1,2,3月
	# 蓝-夏 4,5,6月
	# 黄-秋 7,8,9月
	# 灰-冬 10,11,12月
	
	plt.axvspan(0,1, facecolor='dodgerblue', alpha=0.5)
    for _ in range(2):
        i = _ * 12
        plt.axvspan(i,i+3, facecolor='r', alpha=0.5)
        plt.axvspan(i+3,i+6, facecolor='dodgerblue', alpha=0.5)
        plt.axvspan(i+6,i+9, facecolor='y', alpha=0.5)
        plt.axvspan(i+9,i+12, facecolor='c', alpha=0.5)
	# 设置网格线
    ax.xaxis.grid(linestyle = '-', linewidth=2)
    plt.show()

效果如下

水产 – 活鲤鱼

在这里插入图片描述

  • 从水产品的价格历史变化可以看出:水产品的价格整体呈小幅上升的趋势。鲫鱼、鲤鱼等淡水鱼在2021年的春季出现明显的价格上涨,并在当年夏秋季逐渐回落。
    当时有一份2021年5月份关于淡水鱼价格上升的报道,其中提到了一些可能的原因:
    • 以往淡水鱼价格较低,导致淡水鱼养殖面积减少
    • 春节期间的供应减少了当前的供给
    • 气温较高时活鱼在运输中的损耗大
    • 夏季为淡水鱼的需求旺季

水果 – 西瓜

在这里插入图片描述

  • 水果有着更加明显的季节性

农产品批发价的历史波动幅度

#添加画布 -- 画布属性
ax = plt.figure(figsize=(6, 4), facecolor='c',edgecolor='black', dpi=120).add_subplot(111,  facecolor='aquamarine', alpha=0.1)
# plt.figure(figsize=(20,10),dpi=120)
plt.xlabel("历史价格波动幅度")
plt.ylabel("历史价格平均值")
ax.xaxis.grid(linestyle = '--', linewidth=2, alpha=0.3)
ax.yaxis.grid(linestyle = '--', linewidth=2, alpha=0.3)
# plt.margins(0, 0)

for cate1_k, cate1_v in group:    
    cate1_v = cate1_v.reset_index(drop=True)
    
    price_mean = cate1_v['price'].mean()
    price_std = cate1_v['price'].std()/cate1_v['price'].mean()

	# 散点图
    ax.scatter(price_std, price_mean, s=50)
	
	# 散点标签
    ax.text(price_std, price_mean, cate1_k[1], fontsize=10)

    # plt.grid()
    
#设计标题    
plt.title(cate1_k[0] + "的历史平均价格和价格波动幅度的对比")
    # plt.ylim(0,200)
    #显示图例和图表
    #markerscale 参数调整图例大小
    # plt.legend(markerscale=0.5)
plt.show()

在这里插入图片描述

  • 上面对比了各个农产品的历史平均价格和历史价格的波动幅度:
    • 波动幅度较大的农产品以蔬菜为主。且在蔬菜里面,瓜果类的价格变动会更高,根茎类/菇类的蔬菜价格波动较小,叶菜类的价格波动居中。这可能和不同蔬菜的培育和存储特点有关。
    • 猪肉的位置非常显眼,其在平均价格较高的情况下仍然有较大的价格波动幅度。其价格变化也确实在过去几年引起了人们的普遍关注
    • 西瓜和巨峰葡萄是水果品类中价格波动最大的两个产品。这可能体现了其较强的季节性。
    • 价格较高的牛肉、羊肉等的价格波动幅度较小。
      注:
      历史价格波动幅度 = 历史价格的变异系数 = 历史价格的标准差 历史价格的平均值 \frac{历史价格的标准差}{历史价格的平均值} 历史价格的平均值历史价格的标准差

使用多元回归计算农产品价格的趋势和季节性

如何计算季节性

下面使用多元回归的方法来分析价格的季节性。以西瓜为例,其步骤为:

  1. 选取西瓜的历史批发价数据。本数据集中一共有24个月的数据。
  2. 将每个月的价格视为回归的目标变量。
  3. 将24个月按照顺序赋予从1到24的序号,作为趋势的特征变量。
  4. 对月份进行One-Hot编码,得到从1月到12月的12个特征变量。每条西瓜的价格记录都会在其中某个月的特征变量中标注为1,其他月份则为0。
  5. 基于上述特征变量,针对目标变量价格构建多元回归模型
  6. 以回归模型针对趋势特征变量的系数代表价格变化趋势,以各个月份特征变量的系数代表该月对价格的影响,即季节性影响。
回归分析
import statsmodels.api as sm

# 使用anss 存储模型模拟结果,月份的系数(ceof),以及对应的p值
anss = []

# 月份转成one_hot模式输入,进行回归模拟
m_col = ['mon1', 'mon2', 'mon3', 'mon4', 'mon5', 'mon6', 'mon7', 'mon8', 'mon9', 'mon10', 'mon11', 'mon12']

for k, v in df_group:
    
    ans = list(k)

    v = v.sort_values(by=['year_month', 'mon']).reset_index(drop=True)
              
    ans.append(v['price'].mean())
    ans.append(v['price'].std()/v['price'].mean())
    
    x = v[m_col]
    y = v['price']
    
    model = sm.OLS(y,x)
    results = model.fit()
    
    results_summary = results.summary()
    
    res_df = pd.DataFrame(results_summary.tables[1])
    
    # 存储模型结果
    m_std = []
    m_p_value = []
    for i in range(2,14):
        m_p_value.append(float(res_df[4][i].format(0)))
        m_std.append(float(res_df[1][i].format(0)))
        
    ans.append(m_std)
    ans.append(m_p_value)
    
    sea_m = []
    
    # 统计月份的p值小于0.5的
    cnt = 0
    for i,p in enumerate(m_p_value):
        if p < 0.05:
            cnt += 1
            sea_m.append(i+1)
    
    ans.append(cnt)
    ans.append(sea_m)
    
    anss.append(ans)
 
#print(results.summary())

下面是以西瓜为例的拟合结果,可以看到各个特征变量的参数及其P值的结果:
在这里插入图片描述
在这里插入图片描述

不同农产品的季节性程度对比
#添加画布
ax = plt.figure(figsize=(20, 10), facecolor='aquamarine',edgecolor='black', dpi=120).add_subplot(111,  facecolor='c', alpha=0.1)
# plt.figure(figsize=(20,10),dpi=120)
plt.ylabel("季节对价格的实际影响程度")
plt.xlabel("季节性在统计意义上的季节显著性")
# plt.xlim(0, 1)
# plt.ylim(0,1.5)

ax.xaxis.grid(linestyle = '-', linewidth=2, alpha=0.3, color='white')
ax.yaxis.grid(linestyle = '-', linewidth=2, alpha=0.3, color='white')
# plt.margins(0, 0)
#代码思路:

x_min = 1
x_max = 0
y_min = 1
y_max = 0
for i in range(len(anss)):
    # if anss[i][-2] == 0:
    #     continue
    # if res[i][-3] == "体温计" or res[i][-3] == "消毒酒精":
        # continue
    # plt.scatter(X[y==i,0],X[y==i,1],c=colors[i],s=z[y==i]*20,label = labels[i])
    
    x_min = min(x_min, anss[i][-2]/12)
    x_max = max(x_max, anss[i][-2]/12)
    
    y_min = min(y_min, np.std(anss[i][-4])/anss[i][-6])
    y_max = max(y_max, np.std(anss[i][-4])/anss[i][-6])
    
    plt.scatter(anss[i][-2]/12, np.std(anss[i][-4])/anss[i][2])
    
    plt.text(anss[i][-2]/12, np.std(anss[i][-4])/anss[i][2], anss[i][1], fontsize=8)

# 象限标记
plt.text(0.4, 0.3, "①", fontsize=20, color='red')
plt.text(0.1, 0.3, "②", fontsize=20, color='red')
plt.text(0.1, 0.05, "④", fontsize=20, color='red')
plt.text(0.4, 0.05, "③", fontsize=20, color='red')

# 分割线
plt.vlines(0.2, 0, 0.5, colors='red', linestyles='--')
plt.hlines(0.1, 0, 1, colors='red', linestyles='--')  
# plt.hlines(0.8, 0, 1, colors='red', linestyles='--')  
#设计标题
plt.title("不同农产品的季节性程度对比")

#显示图例和图表
#markerscale 参数调整图例大小
plt.legend(markerscale=0.5)
plt.show()

在这里插入图片描述
上图的横坐标是农产品的季节性在统计意义上的显著性程度,纵坐标是季节性对农产品价格的实际影响程度。二者的数值越高,则代表农产品的季节性越强烈。基于这两个数值,分别以0.2和0.1作为阈值,可以将农产品划分为四组:

  • 第1组是我们最感兴趣的,其既有统计意义上显著性,在实际意义上也大幅影响价格波动。这一组以蔬菜和水果为主。
  • 唯一的例外是猪肉。虽然猪肉有一定的季节性,但在过去几年,由于其降价趋势的影响,其季节性体现得不明显。
  • 第4组的农产品虽然有统计意义上显著的季节性,但实际对价格影响较小,在实际生活中往往可以忽略不记。
    ps:
    季节性在统计意义上的季节显著性 = 通过显著性检验的月份 12 季节性在统计意义上的季节显著性 = \frac{通过显著性检验的月份}{12} 季节性在统计意义上的季节显著性=12通过显著性检验的月份
    季节性在统计意义上的季节显著性 = 季节性波动的标准差 价格的平均值 季节性在统计意义上的季节显著性 = \frac{季节性波动的标准差}{价格的平均值} 季节性在统计意义上的季节显著性=价格的平均值季节性波动的标准差
热力图
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
# sphinx_gallery_thumbnail_number = 2

# 筛选前15个产品
vegetables = [h[1] for h in anss[:15]]
# farmers =[] = ["Farmer Joe", "Upland Bros.", "Smith Gardening",
#            "Agrifun", "Organiculture", "BioGoods Ltd.", "Cornylee Corp."]
farmers = [str(i) + "月" for i in range(1, 13)]

# 回归模型对应月份的系数
tmp_harvest = [h[4] for h in anss[:15]]

# 画布
fig, ax = plt.subplots(figsize=(20,10))
im = ax.imshow(tmp_harvest,  cmap="RdYlBu_r")

# 设置热力图的边框
cbar = ax.figure.colorbar(im, ax=ax)
cbar.ax.set_ylabel("harvest legend", rotation=-90, va="bottom")

# 设置x,y轴刻度
ax.set_xticks(np.arange(len(farmers)))
ax.set_yticks(np.arange(len(vegetables)))

# 将任何其他类型的值作为标签.赋值给之前已经设置过的set_xtick,set_yticks. 
ax.set_xticklabels(farmers)
ax.set_yticklabels(vegetables)

# x轴的坐标旋转45度
plt.setp(ax.get_xticklabels(), rotation=45, ha="right",
         rotation_mode="anchor")
# 设置网格图
ax.grid(which="minor", color="w", linestyle='-', linewidth=3)
ax.tick_params(which="minor", bottom=False, left=False)


# 设置热力图的值
for i in range(len(vegetables)):
    for j in range(len(farmers)):
        text = ax.text(j, i, round(tmp_harvest[i][j], 3),
                       ha="center", va="center", color="black")

ax.set_title("农产品季节性价格变化热力图")
fig.tight_layout()
plt.show()

在这里插入图片描述
季节性价格热力图中,正数代表价格在当季的提升趋势,负数代表价格的下降趋势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值