小白第一次写,欢迎大佬们指教,在此谢过。
本文主要介绍运用ARMA开展销售额预测
第一步当然还是引入所需要的数据包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.arima_model import ARMA, ARIMA
import statsmodels.api as sm
import warnings
from itertools import product
from datetime import datetime, timedelta
import calendar
完成数据加载
# 数据加载
df = pd.read_csv('./sales.csv', encoding='gbk')
print(df.head())
df.columns = ['time', 'amount'] #修改表头
print(df.head())
防止中文导致可能出现一些不可名状的BUG,将表头进行修改,打印结果如下:
将时间所谓索引序列,方便后续的数据切分和检索
# 将时间作为df的索引
df.time = pd.to_datetime(df.time, format="%Y年%m月")
df.index = df.time #方便之后用时间索引
df_month = df #copy数据
product 用于多个可迭代对象的笛卡尔积(Cartesian Product),它和嵌套的For循环等价。
product(A,B) = ((x,y) for x in A for y in B)
example:
from itertools import product as product
A = [1, 2, 3]
B = [4, 5, 6]
for item in product(A, B):
print(item)
(1, 4)
(1, 5)
(1, 6)
(2, 4)
(2, 5)
(2, 6)
(3, 4)
(3, 5)
(3, 6)
为ARIMA设置参数范围 ,从数据可以看出,是上升的,是非平稳的,所以用d=1做了一阶差分,把序列变成平稳序列
# 设置参数范围
ps = range(0, 5)
qs = range(0, 5)
ds = range(1, 2) #d=1
parameters = product(ps, ds, qs)
parameters_list = list(parameters)
模型评估采用AIC(赤池信息量准则)标准,赤池信息量准则是建立在熵概念基础上的,可以衡量所估计模型的复杂度和模型拟合数据的优良性。
AIC鼓励数据拟合的优良性但是尽量避免出现过度拟合(Overfitting)的情况。所以优先考虑的模型应是AIC值最小的那一个。假设在n个模型中做出选择,可一次算出n个模型的AIC值,并找出最小AIC值相对应的模型作为选择对象。
AIC刚开始设置为无穷大,然后去与模型计算的AIC比较,从而找出最优的模型。
# 寻找最优ARMA模型参数,即best_aic最小
results = []
best_aic = float("inf") # 正无穷
for param in parameters_list:
try:
#生成25个模型,每个模型都用amount属性做训练
# SARIMAX 包含季节趋势因素的ARIMA模型
model = sm.tsa.statespace.SARIMAX(df_month.amount,
order=(param[0], param[1], param[2]),
enforce_stationarity=False,
enforce_invertibility=False).fit()
except ValueError:
print('参数错误:', param)
continue
aic = model.aic
if aic < best_aic:
best_model = model
best_aic = aic
best_param = param
results.append([param, model.aic])
# 输出最优模型
print('最优模型: ', best_model.summary())
最优模型参数如下:
为了对接下来的四个月做预测,首先要做的就是在数据集中增加未来四个月的字段,然后便于模型预测写入。
# 设置future_month,需要预测的时间date_list
df_month2 = df_month[['amount']]
future_month = 4
last_month = pd.to_datetime(df_month2.index[len(df_month2)-1])
date_list = []
for i in range(future_month):
# 计算下个月有多少天
year = last_month.year
month = last_month.month
next_month_days = calendar.monthrange(year, month)[1]
#print(next_month_days)
last_month = last_month + timedelta(days=next_month_days)
date_list.append(last_month)
print('date_list=', date_list)
# 添加未来要预测的4个月
future = pd.DataFrame(index=date_list, columns= df_month.columns)
df_month2 = pd.concat([df_month2, future])
df_month2
可以看到 增加了四个月待模型预测
开始预测
# get_prediction得到的是区间,使用predicted_mean
df_month2['forecast'] = best_model.get_prediction(start=0, end=len(df_month2)).predicted_mean
print(df_month2)
可以看出前两个月明显预测有问题,将其去掉
# 第两个点预估异常,可以去掉
df_month2['forecast'][:1] =[None,None]
print(df_month2)
将预测结果使用plt输出
#In[]
# 沪市指数预测结果显示
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.figure(figsize=(30,7))
df_month2.amount.plot(label='实际销售额')
df_month2.forecast.plot(color='r', ls='--', label='预测销售额')
plt.legend()
plt.title('天河超市销售额(月)')
plt.xlabel('时间')
plt.ylabel('销售额')
plt.show()