python实现灰色预测模型(GM11)——以预测股票收盘价为例

时间:2024-02-26 08:37:59

程序简介

利用灰色预测GM11模型预测股票收盘价,由于灰色预测模型适合短期预测和小样本,所以程序输入数据为5个,输出为1个,进行动态建模
程序输入:原序列、需要往后预测的个数
程序输出:预测值、模型结构(后验差比、发展系数、灰色作用量)

灰色预测模型(GM11)即对原始数据作累加生成(或其它方法生成)得到近似的指数规律再进行建模的方法。灰色预测模型对于不同问题采用不同模型,模型主要解决生成序列是有指数变化规律,只能描述单调的变化过程。

程序/数据集下载

点击进入下载地址

代码分析

导入模块、路径

# -*- coding: utf-8 -*-
from Module.BuildModel import GM11
from sklearn.metrics import mean_absolute_error
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os

#路径目录
baseDir = \'\'#当前目录
staticDir = os.path.join(baseDir,\'Static\')#静态文件目录
resultDir = os.path.join(baseDir,\'Result\')#结果文件目录

读取上证指数数据分割训练和测试集,本文只使用收盘价,查看内容

#读取数据
data = pd.read_csv(staticDir+\'/000001.csv\',encoding=\'gbk\')
train = data[\'收盘价\'].values[-15:-10]#训练数据
test = data[\'收盘价\'].values[-10:]#测试数据
data.head()
日期 股票代码 名称 收盘价 最高价 最低价 开盘价 前收盘 涨跌额 涨跌幅 成交量 成交金额
0 2020-02-18 \'000001 上证指数 2984.9716 2990.6003 2960.7751 2981.4097 2983.6224 1.3492 0.0452 311665913 3.74998562648e+11
1 2020-02-17 \'000001 上证指数 2983.6224 2983.6371 2924.9913 2924.9913 2917.0077 66.6147 2.2837 313198007 3.67014340129e+11
2 2020-02-14 \'000001 上证指数 2917.0077 2926.9427 2899.5739 2899.8659 2906.0735 10.9342 0.3763 250650627 3.08080368726e+11
3 2020-02-13 \'000001 上证指数 2906.0735 2935.4060 2901.2425 2927.1443 2926.8991 -20.8256 -0.7115 274804844 3.34526327364e+11
4 2020-02-12 \'000001 上证指数 2926.8991 2926.8991 2892.4240 2895.5561 2901.6744 25.2247 0.8693 248733429 2.97534420493e+11

使用GM11函数进行动态建模,打印结论,GM11函数位于项目文件夹的Module/BuildModel.py,下文会给出代码

#GM11动态建模
yPre = []
for i in range(test.shape[0]):
    #只预测1个数
    result = GM11(train,1)
    yPre.append(result[\'predict\'][\'value\'][0])
    #更新训练集
    train = train.tolist()[:-1]
    train.append(test[i])
    train = np.array(train).reshape(-1)
#计算MAE
MAE = mean_absolute_error(test,yPre)
#打印模型
print(result[\'C\'][\'desc\'])
print(result[\'a\'][\'desc\'],np.round(result[\'a\'][\'value\'],2))
print(result[\'b\'][\'desc\'],np.round(result[\'b\'][\'value\'],2))
后验差比<=0.65,模型精度等级为勉强
发展系数 0.07
灰色作用量 150.96

这是上文GM11的函数,该代码可直接运行进行测试,函数输入为原序列和预测个数,输出为模型各参数和序列值

# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
 
def GM11(x,n):
    \'\'\'
    灰色预测
    x:序列,numpy对象
    n:需要往后预测的个数
    \'\'\'
    x1 = x.cumsum()#一次累加  
    z1 = (x1[:len(x1) - 1] + x1[1:])/2.0#紧邻均值  
    z1 = z1.reshape((len(z1),1))  
    B = np.append(-z1,np.ones_like(z1),axis=1)  
    Y = x[1:].reshape((len(x) - 1,1))
    #a为发展系数 b为灰色作用量
    [[a],[b]] = np.dot(np.dot(np.linalg.inv(np.dot(B.T, B)), B.T), Y)#计算参数  
    result = (x[0]-b/a)*np.exp(-a*(n-1))-(x[0]-b/a)*np.exp(-a*(n-2))  
    S1_2 = x.var()#原序列方差
    e = list()#残差序列
    for index in range(1,x.shape[0]+1):
        predict = (x[0]-b/a)*np.exp(-a*(index-1))-(x[0]-b/a)*np.exp(-a*(index-2))
        e.append(x[index-1]-predict)
    S2_2 = np.array(e).var()#残差方差
    C = S2_2/S1_2#后验差比
    if C<=0.35:
        assess = \'后验差比<=0.35,模型精度等级为好\'
    elif C<=0.5:
        assess = \'后验差比<=0.5,模型精度等级为合格\'
    elif C<=0.65:
        assess = \'后验差比<=0.65,模型精度等级为勉强\'
    else:
        assess = \'后验差比>0.65,模型精度等级为不合格\'
    #预测数据
    predict = list()
    for index in range(x.shape[0]+1,x.shape[0]+n+1):
        predict.append((x[0]-b/a)*np.exp(-a*(index-1))-(x[0]-b/a)*np.exp(-a*(index-2)))
    predict = np.array(predict)
    return {
            \'a\':{\'value\':a,\'desc\':\'发展系数\'},
            \'b\':{\'value\':b,\'desc\':\'灰色作用量\'},
            \'predict\':{\'value\':result,\'desc\':\'第%d个预测值\'%n},
            \'C\':{\'value\':C,\'desc\':assess},
            \'predict\':{\'value\':predict,\'desc\':\'往后预测%d个的序列\'%(n)},
            }
 
if __name__ == "__main__":
    data = np.array([1.2,2.2,3.1,4.5,5.6,6.7,7.1,8.2,9.6,10.6,11,12.4,13.5,14.7,15.2])
    x = data[0:10]#输入数据
    y = data[10:]#需要预测的数据
    result = GM11(x,len(y))
    predict = result[\'predict\'][\'value\']
    predict = np.round(predict,1)
    print(\'真实值:\',y)
    print(\'预测值:\',predict)
    print(result)

进行观测值预测值可视化

#用来正常显示中文标签
plt.rcParams[\'font.sans-serif\']=[\'SimHei\'] 
#用来正常显示负号
plt.rcParams[\'axes.unicode_minus\']=False
plt.plot(range(test.shape[0]),yPre,label="预测值")
plt.plot(range(test.shape[0]),test,label="观测值")
plt.legend()
plt.title(\'GM11预测效果,MAE:%2f\'%MAE)
plt.savefig(resultDir+\'/GM11预测效果.png\',dpi=100,bbox_inches=\'tight\')