首页 / 操作系统 / Linux / 二次指数平滑预测法 Python实现
从以往的时间序列值,进行指数平滑,做两次预测出下一个时间的估计值。目录结构如下:Python代码如下:forecast.py# -*-coding:utf-8 -*-
# Time:2015.11.25 sangjin
__author__ = "hunterhug"
import matplotlib
#matplotlib.use("Agg")
#matplotlib.use("TkAgg")
#matplotlib.use("gtk")
import matplotlib.pyplot as plt
from matplotlib.pyplot import savefig
from matplotlib.font_manager import FontProperties
from operator import itemgetter
#读取execel使用(支持07)
from openpyxl import Workbook
#写入excel使用(支持07)
from openpyxl import load_workbook
import os
def judgefile():
path = input("请输入该目录下的excel文件名:") # file path
if os.path.isfile(path):
return path.lower()
else:
print("文件不存在")
return judgefile()def writeexcel07(path, content, name="Sheet1", sheetnum=0):
wb=Workbook()
#sheet=wb.add_sheet("xlwt3数据测试表")
sheet=wb.create_sheet(sheetnum,name)
# values = [["名称", "Hadoop编程实战", "hbase编程实战", "lucene编程实战"], ["价格", "52.3", "45", "36"], ["出版社", "机械工业出版社", "人民邮电出版社", "华夏人民出版社"], ["中文版式", "中", "英", "英"]]
for i in range(0,len(content)):
for j in range(0,len(content[i])):
sheet.cell(row = i+1,column= j+1).value = content[i][j] # sheet.cell(row = 1,column= 2).value="温度"
wb.save(path)
print("写入数据成功!")def read07excel(path):
excelcontent = []
wb2=load_workbook(path)
sheetnames = wb2.get_sheet_names()
ws=wb2.get_sheet_by_name(sheetnames[0])
row=ws.get_highest_row()
col=ws.get_highest_column()
# print("列数: ",ws.get_highest_column())
# print("行数: ",ws.get_highest_row()) for i in range(0,row):
rowcontent = []
for j in range(0,col):
if ws.rows[i][j].value:
rowcontent.append(ws.rows[i][j].value)
excelcontent.append(rowcontent)
print("读取数据成功!")
return excelcontent
def calvalue(excel, a):
date = [] # x label date
data = [] # y label data for i in range(2,len(excel)-1):
data.append(float(excel[i][1]))
date.append(excel[i][0]) e1 = [data[0]] # one time forecast for i in range(0,len(data)):
next = data[i] * a + e1[i] * (1 - a)
e1.append(next) e1e = [] # one time absoultion error
for i in range(0,len(data)):
e1e.append(abs(data[i]-e1[i])) e1e2 = sum(e1e) e2 = [data[0]] # second time forecast
for i in range(0,len(data)):
next = e1[i] * a + e2[i] * (1 - a)
e2.append(next) e2e = [] # second time absoultion error
for i in range(0,len(data)):
e2e.append(abs(data[i]-e2[i])) e2e2 = sum(e2e) e1y = e1[len(e1)-1] # one time forecast value
e2y = e2[len(e2)-1] # two time forecast value
return [a, e1y, e2y, e1e2, e2e2]def calvaluetop5(excel, step = 0.01):
initvalue = 1.0
all = []
top5 =[]
while initvalue <= 1.0 and initvalue >= 0:
all.append(calvalue(excel, initvalue))
initvalue = initvalue -step
d = {}
for i in range(0, len(all)):
d.setdefault(i, all[i][3])
d1 = sorted(d.items(), key=itemgetter(1))
#print(d1)
topnum = len(d1)
if topnum>=5:
topnum = 5
else:
pass
for i in range(0,topnum):
pos = d1[i][0]
top5.append(all[pos])
return top5def judgestep():
try:
a = float(input("请选择系数变化步长(范围0~1):")) # change var
except:
print("请输入数字好么...")
return judgestep()
while a > 1 or a < 0:
print("输入的步长范围在0-1之间")
return judgestep()
return adef judge():
try:
a = float(input("请输入变化系数a:")) # change var
except:
print("请输入数字好么...")
return judge()
while a > 1 or a < 0:
print("输入的变化系数范围在0-1之间")
return judge()
return a
def single(a,path):
excel = read07excel(path)
title1 = excel[0][0]
title2 = excel[1]
# print(excel) title = ":".join(excel[0])
date = [] # x label date
data = [] # y label data for i in range(2,len(excel)-1):
data.append(float(excel[i][1]))
date.append(excel[i][0])
# print("/n",data)
# print(title,data,date) e1 = [data[0]] # one time forecast for i in range(0,len(data)):
next = data[i] * a + e1[i] * (1 - a)
e1.append(next)
# print("/n",e1) e1e = [] # one time absoultion error
for i in range(0,len(data)):
e1e.append(abs(data[i]-e1[i]))
# print("/n",e1e) ele2 = sum(e1e)
# print(ele2) e2 = [data[0]] # second time forecast
for i in range(0,len(data)):
next = e1[i] * a + e2[i] * (1 - a)
e2.append(next)
# print("/n",e2) e2e = [] # second time absoultion error
for i in range(0,len(data)):
e2e.append(abs(data[i]-e2[i]))
# print("/n",e2e) e2e2 = sum(e2e)
# print(e2e2) e1y = e1[len(e1)-1] # one time forecast value
e2y = e2[len(e2)-1] # two time forecast value content = [[title1,"可变系数a=",a]]
content.append([title2[0],title2[1],"一次指数平滑预测值","绝对误差","二次指数平滑","绝对误差"]) datas = [date, data, e1[:len(e1)-1], e1e, e2[:len(e2)-1], e2e] datast = [[r[col] for r in datas] for col in range(len(datas[0]))]
content[len(content):] = datast yu1 = ["", e2y, e1y, ele2, e2y, e2e2]
yu2 = ["", "最终预测值", "一次指数平滑预测值", "一次指数平滑绝对误差累加", "二次指数平滑预测值", "一次指数平滑绝对误差累加"]
content.append(yu1)
content.append(yu2)
content.append(["说明:请手动插入走势图。此文件为自动计算生成"])
# print(content) path1 =path.replace(".xlsx", "(结果生成).xlsx")
writeexcel07(path1, content, "生成表")
print("请打开所在目录生成的excel文件(结果生成)")
plt.close("all")
font = FontProperties(fname=r"c:windowsfontssimsun.ttc", size=14)
plt.figure(figsize=(10,7))
num = range(0,len(date))
plt.plot(num, data, "b-*", label="原始数据")
plt.plot(num, e1[:len(e1)-1], "r*-", label="一次指数预测")
plt.plot(num, e2[:len(e2)-1], "g*-", label="二次指数预测")
bottomtitle1 = "
一次预测值:"+str(e1y)+" 误差和:"+str(ele2)
bottomtitle = bottomtitle1 + "
二次预测值:"+str(e2y)+" 误差和:"+str(e2e2)
plt.title("指数平滑法预测走势图(时间序列)变化系数a={0:3f}".format(a)+bottomtitle, fontproperties=font) # simfang.ttf
# plt.text(0, 0, bottomtitle, fontproperties=font)
plt.xlabel("时间间隔", fontproperties=font)
plt.ylabel("成交额", fontproperties=font)
legend = plt.legend(loc="upper right", prop=font)
# legend = plt.legend(loc="upper right", shadow=True, prop=font)
legend.get_frame().set_facecolor("white")
plt.grid(True) # Tweak spacing to prevent clipping of ylabel
plt.subplots_adjust(left=0.15)
plt.show()
savefig("Fig.png")
def begin():
sangjin = """
-----------------------------------------
| 欢迎使用二次指数平滑法预测未来值 |
| |
| 使用方法: |
| 1.根据提示进行操作 |
| 2.输出为预测走势图,以及处理后的excel |
-----------------------------------------
| ??木公司花名:桑槿 |
| 新浪微博:一只尼玛 |
| 微信/QQ:569929309 |
-----------------------------------------
"""
print(sangjin)def loop(path):
choice1 = input("自动计算变化系数请选择y,手动请选择n
")
if choice1 == "y":
step = judgestep()
p5 = calvaluetop5(read07excel(path), step)
print("总误差最小的前五个是")
for i in p5:
print("变化系数:{0:3f} 预测值:{1:3f} 总误差值:{2:3f}".format(i[0],i[2],i[4]))
single(p5[0][0],path)
else:
a = judge()
single(a,path)
def loop3(path):
choice2 = input("如果想操作其他文件请选择y,退出选择n,其他操作按任意键
")
if choice2 == "y":
loop1()
elif choice2 == "n":
print("正在退出中...
"*6)
print("正在退出中...谢谢")
exit(1)
else:
loop(path)
loop3(path)def loop1():
path = judgefile()
loop(path)
loop3(path)begin()
loop1()输入excel格式如下:输出结果:代码参考:下载------------------------------------------分割线------------------------------------------免费下载地址在 http://linux.linuxidc.com/用户名与密码都是www.linuxidc.com具体下载目录在 /2015年资料/11月/27日/二次指数平滑预测法 Python实现/下载方法见 http://www.linuxidc.com/Linux/2013-07/87684.htm------------------------------------------分割线------------------------------------------本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-11/125603.htm