歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> 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 top5

def 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 a

def 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:\windows\fonts\simsun.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 = '\n一次預測值:'+str(e1y)+"\t誤差和:"+str(ele2)
    bottomtitle = bottomtitle1 + '\n二次預測值:'+str(e2y)+"\t誤差和:"+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\n")
    if choice1 == 'y':
        step = judgestep()
        p5 = calvaluetop5(read07excel(path), step)
        print('總誤差最小的前五個是')
        for i in p5:
            print('變化系數:{0:3f}\t預測值:{1:3f}\t總誤差值:{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,其他操作按任意鍵\n")
    if choice2 == 'y':
        loop1()
    elif choice2 == 'n':
        print("正在退出中...\n"*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

------------------------------------------分割線------------------------------------------

Copyright © Linux教程網 All Rights Reserved