数模竞赛-预测方法

灰色预测模型

GM(1,1)只适合具有较强指数规律的序列,GM(2,1)、DGM和Verhulst模型适用于非单调摆动发展序列或有饱和S形序列。

GM(1,1)预测方法

GM(1,1)预测模型定义:

1阶微分方程,只含1个变量。

已知参考数列x(0)=(x(0)(1),x(0)(2),,x(0)(n))1次累加生成序列1-AGO定义为x(1)=(x(1)(1),x(1)(2),,x(1)(n)),式中x(1)(k)=i=1kx(0)(i),1kn,且x(1)的均值生成序列为z(1)=(z(1)(2),z(1)(3),,z(1)(n)),其中z(1)(k)=0.5x(1)(k)+0.5x(1)(k+1),2kn

建立灰微分方程x(0)(k)+az(1)(k)=b,2kn,其对应的白化微分方程为dx(1)(t)dt+ax(1)(t)=b,记:

u=[a,b]T,Y=[x(0)(2),x(0)(3),,x(0)(n)]T,B=[z(1)(2)1z(1)(3)1z(1)(n)1]

由最小二乘法求使得J(u)=(YBu)T(YBu)达到最小估计值的uu^=[a^,b^]T=(BTB1)1BTY,求解得:

x^(1)(k+1)=(x(0)(1)b^a^)ea^k+b^a^,k0

GM(1,1)模型预测步骤:

当计算序列级比2kn,λ(k)=x(0)(k1)x(0)(k)Θ,Θ=(e2n+1,e2n+1),如果不落在范围Θ中需要进行平移变换,选取充分大的c>0进行变换y(0)(k)=x(0)(k)+c,1kn,再计算级比。

检验预测值:

计算相对误差δ(k)=|x(0)(k)x^(0)(k)|x(0)(k),1kn,当δ(k)<0.2达到一般要求,δ(k)<0.1达到较高要求。

计算级比偏差值ρ(k)=|1(10.5a^1+0.5a^)λ(k)|,当ρ(k)<0.2达到一般要求,ρ(k)<0.1达到较高要求。

例题1:

给定Leq有:71.1,72.4,72.4,72.1,71.4,72.0,71.6,预测下一个。

代码:

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import numpy,sympy
x0=numpy.array([71.1,72.4,72.4,72.1,71.4,72.0,71.6])
n=len(x0)
lamda=x0[:-1]/x0[1:]
b1=[min(lamda),max(lamda)]
b2=[numpy.exp(-2/(n+1)),numpy.exp(2/(n+1))] #求Theta

x1=numpy.cumsum(x0) #前缀和
z=(x1[:-1]+x1[1:])/2
B=numpy.vstack([-z,numpy.ones(n-1)]).T
u=numpy.linalg.pinv(B)@x0[1:]
sympy.var('t')
sympy.var('x',cls=sympy.Function)
eq=x(t).diff(t)+u[0]*x(t)-u[1]
xt0=sympy.dsolve(eq,ics={x(0):x0[0]})
xt0=xt0.args[1]
xt=sympy.lambdify(t,xt0,'numpy')
t=numpy.arange(n+1)
xh=xt(t)
x0h=numpy.hstack([x0[0],numpy.diff(xh)]) #差分:还原
x1993=x0h[-1]

cha=x0-x0h[:-1] #误差分析
delta=abs(cha/x0)*100
rho=abs(1-(1-0.5*u[0])/(1+0.5*u[0])*lamda)

print(round(x1993,4))

GM(2,1)预测方法

设原始数列x(0)=(x(0)(1),x(0)(2),,x(0)(n)),其一次累加生成序列1-AGO为x(1)=(x(1)(1),x(1)(2),,2(1)(n)),一次累减生成序列1-IAGO为α(1)x(0)=(α(1)x(0)(2),,α(1)x(0)(n)),其中α(1)x(0)(k)=x(0)(k)x(0)(k1),k=2,3,,n。设z(1)=(z(1)(2),z(1)(3),,z(1)(n)),则称α(1)x(0)(k)+a1x(0)(k)+a2z(1)(k)=bGM(2,1)模型。称d2x(1)(t)dt2+a1dx(1)(t)dt+a2x(1)(t)=bGM(2,1)模型的白化方程。

设:

B=[x(0)(2)z(1)(2)1x(0)(3)z(1)(3)1x(0)(n)z(1)(n)1],Y=[α(1)x(0)(2)α(1)x(0)(3)α(1)x(0)(n)]

则参数序列u=[a1,a2,b]T最小二乘估计为u^=(BTB)1BTY

例题2:

已知x(0)=(41,49,61,78,96,104),建立GM(2,1)模型。

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy,sympy
x0=numpy.array([41,49,61,78,96,104])
n=len(x0)
x1=numpy.cumsum(x0) #1-AGO
ax0=numpy.diff(x0) #1-IAGO
z=(x1[1:]+x1[:-1])/2
B=numpy.vstack([-x0[1:],-z,numpy.ones(n-1)]).T
u=numpy.linalg.pinv(B)@ax0
sympy.var('t')
sympy.var('x',cls=sympy.Function)
eq=x(t).diff(t,2)+u[0]*x(t).diff(t)+u[1]*x(t)-u[2]
s=sympy.dsolve(eq,ics={x(0):x1[0],x(5):x1[-1]})
xt=s.args[1] #符号表达式
x=sympy.lambdify(t,xt,'numpy') #匿名函数
xh1=x(numpy.arange(n))
xh0=numpy.hstack([x0[0],numpy.diff(xh1)])
print(numpy.round(xh0,4)) #预测值
ea=x0-xh0 #残差
er=abs(ea)/x0*100 #相对误差

DGM(2,1)模型

一些定义同上。

α(1)x(0)(k)+αx(0)(k)=bDGM(2,1)模型,d2x(1)(t)dt+adx(1)(t)dt=bDGM(2,1)模型的白化方程。若u=[a,b]T,更改定义:

B=[x(0)(2)1x(0)(3)1x(0)(n)1]

该模型参数最小二乘估计满足u^=(BTB)1BTY

例题3:

已知x(0)=(2.874,3.278,3.39,3.679,3.77,3.8),建立DGM(2,1)模型。

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy,sympy
x0=numpy.array([2.874,3.278,3.39,3.679,3.77,3.8])
n=len(x0)
ax0=numpy.diff(x0)
B=numpy.vstack([-x0[1:],numpy.ones(n-1)]).T
u=numpy.linalg.pinv(B)@ax0
sympy.var('t')
sympy.var('x',cls=sympy.Function)
eq=x(t).diff(t,2)+u[0]*x(t).diff(t)-u[1]
s=sympy.dsolve(eq,ics={x(0):x0[0],x(t).diff(t).subs(t,0):x0[0]})
xt=s.args[1]
x=sympy.lambdify(t,xt,'numpy')
xh1=x(numpy.arange(n))
xh0=numpy.hstack([x0[0],numpy.diff(xh1)])
print(numpy.round(xh0,4))
ea=x0-xh0
er=abs(ea)/x0*100

Verhulst模型

一些定义同GM(1,1)模型,设a,b为参数,称x(0)(k)+az(1)(k)=b[z(1)(k)]2dx(1)(t)dt+ax(1)(t)=b[x(1)(t)]2为白化方程,t为时间。

参数序列为u=[a,b]T更改定义:

B=[z(1)(2)(z(1)(2))2z(1)(3)(z(1)(3))2z(1)(n)(z(1)(n))2],Y=[x(0)(2)x(0)(3)x(0)(n)]

最小二乘估计同上,白化方程的解为x(1)(t)=a^x(0)(1)b^x(0)(1)+(a^b^x(0)(1))ea^t,相应的时间相应序列为x(1)(k+1)=a^x(0)(1)b^x(0)(1)+(a^b^x(0)(1))ea^k,同样累减还原式为x^(0)(k+1)=x^(1)(k+1)x^(1)(k)

例题4:

已知x(0)=(4.93,2.33,3.87,4.35,6.63,7.15,5.37,6.39,7.81,8.35),建立Verhulst模型。

python
1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy
x0=numpy.array([4.93,2.33,3.87,4.35,6.63,7.15,5.37,6.39,7.81,8.35])
n=len(x0)
x1=numpy.cumsum(x0)
z=(x1[1:]+x1[:-1])/2
B=numpy.vstack([-z,z**2]).T
u=numpy.linalg.pinv(B)@x0[1:]
x=lambda t:u[0]*x0[0]/(u[1]*x0[0]+(u[0]-u[1]*x0[0])*numpy.exp(u[0]*t)) #别求解了直接上解吧
xh1=x(numpy.arange(n))
xh0=numpy.hstack([x0[0],numpy.diff(xh1)])
print(numpy.round(xh0,4))
ea=x0-xh0
er=abs(ea)/x0*100

神经元网络

单层感知器模型

设连接权为X=[x1,x2,,xm]T,W=[w1,w2,,2m]T,于是网络输入为u=i=1mwixi=WTX

激活/激励/活化函数有四种:线性函数f(u)=ku+c;非线性斜面函数;阈值/阶跃函数;sigmoid函数f(u)=11+eu,将(,+)映射到(0,1);tanh函数f(u)=eueueu+eu,将(,+)映射到(1,1)

感知器模型,其中wi为系数,b为常数项,y为分类预测值:

v=i=1mwixi+b,y={1,v0,0,v<0

例题:解决简单分类问题,将四个输入列向量分成两类,输入向量为:

P=[0.50.50.30.00.50.50.51.0]

目标分类向量T=[1,1,0,0],试预测新输入向量p=[0.5,0.2]T目标值。

代码:

python
1
2
3
4
5
6
from sklearn.linear_model import Perceptron
import numpy
x0=numpy.array([[-0.5,-0.5,0.3,0.0],[-0.5,0.5,-0.5,1.0]]).T
y0=numpy.array([1,1,0,0])
md=Perceptron().fit(x0,y0)
print(md.coef_,md.intercept_,md.score(x0,y0),md.predict([[-0.5,0.2]])) #系数 常数项 精度 预测值

BP神经网络

数据预处理时,将效益型数据映射到相应需要的[0,1][1,1]区间上,有三种方法。当激活函数为sigmoid函数时使用x~=xxminxmaxxmin。当激活函数为tanh函数时使用x~=2(xxmin)xmaxxmin1。也可以用一般标准化变换x~=xxσ

例题:根据前十所公司信用,判断后两所公司是否为ST公司。

对效益型指标x1,x3,x4,x5,x6,x7,x8用公式xi~=xiximinximaxximin,成本型指标x2用公式x2~=x2maxx2x2maxx2min。有一个隐层,隐层神经元个数用30,激活函数用sigmoid函数。

代码:

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sklearn.neural_network import MLPClassifier
import numpy
a=numpy.loadtxt("xxx.txt")
x0=a[:10,:]
x=a[10:,:]
m1=x0.max(axis=0)
m2=x0.min(axis=0)
bx0=(x0-m2)/(m1-m2)
bx0[:,1]=(m1[1]-x0[:,1])/(m1[1]-m2[1])
y0=numpy.hstack([numpy.zeros(5),numpy.ones(5)])
md=MLPClassifier(solver="lbfgs",activation="logistic",hidden_layer_sizes=30).fit(bx0,y0)
bx=(x-m2)/(m1-m2)
bx[:,1]=(m1[1]-x[:,1])/(m1[1]-m2[1])
yh=md.predict(bx)
print(yh,md.predict_proba(bx),md.score(bx0,y0)) #待测样本类别 属于各类别概率 回代准确率

例题:给出1990-2009减公路客运人口数量、机动车数量、公路面积、客运量,已知2010和2011年人口数量、机动车数量、公路面积,预测客运量。

处理人口数量、机动车数量、公路面积分别为x1,x2,x3,选择公式xi~=2(xiximin)ximaxximin1。设置隐层神经元为10个,激活函数取线性函数。

代码:

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from sklearn.neural_network import MLPRegressor
import numpy,pylab
a=numpy.loadtxt('xxx.txt')
x0=a[:,:3]
y0=a[:,3]
m1=x0.max(axis=0)
m2=x0.min(axis=0)
bx0=2*(x0-m2)/(m1-m2)-1
md=MLPRegressor(solver='lbfgs',activation='identity',hidden_layer_sizes=10).fit(bx0,y0)
x=numpy.array([[73.39,75.55],[3.9635,4.0975],[0.9880,1.0268]]).T
bx=2*(x-m2)/(m1-m2)-1
yh=md.predict(bx)
print(numpy.round(yh,4)) #预测值
yh0=md.predict(bx0)
delta=abs(yh0-y0)/y0*100
print(numpy.round(delta,4)) #相对误差
t=numpy.arange(1990,2010)
pylab.rc('font',sizeof=15)
pylab.rc('font',family='SimHei')
pylab.plot(t,y0,'--o',label='原始数据')
pylab.plot(t,yh0,'-*',label='预测数据')
pylab.xticks(t,rotation=55)
pylab.legend()
pylab.show()