通过模型算法,熟练对Matlab的应用。
学习视频链接:
https://www.bilibili.com/video/BV1EK41187QF?p=48&vd_source=67471d3a1b4f517b7a7964093e62f7e6
灰色系统理论在另一篇博客中已经阐述过了,此处不作赘述。
参考链接:【学习笔记】Matlab和python双语言的学习(灰色关联分析法)
设 x ( 0 ) = ( x ( 0 ) ( 1 ) , x ( 0 ) ( 2 ) , . . . , x ( 0 ) ( n ) ) x^{(0)}=(x^{(0)}(1),x^{(0)}(2),...,x^{(0)}(n)) x(0)=(x(0)(1),x(0)(2),...,x(0)(n))是最初的非负数据列,我们可以对其累加,得到新的数据列 x ( 1 ) x^{(1)} x(1)
x ( 1 ) = ( x ( 1 ) ( 1 ) , x ( 1 ) ( 2 ) , … , x ( 1 ) ( n ) ) x^{(1)}=\left(x^{(1)}(1),x^{(1)}(2),\ldots,x^{(1)}(n)\right) x(1)=(x(1)(1),x(1)(2),…,x(1)(n))
其中: x ( 1 ) ( m ) = ∑ i = 1 m x ( 0 ) ( i ) , m = 1 , 2 , . . . , n x^{(1)}(m)=\sum_{\mathrm{i}=1}^{\mathrm{m}}x^{(0)}(i),m=1,2,...,n x(1)(m)=∑i=1mx(0)(i),m=1,2,...,n
首先计算原始数据级比 σ ( k ) = x ( 0 ) ( k ) x ( 0 ) ( k − 1 ) ( k = 2 , 3 , … , n ) \sigma(k)=\frac{x^{(0)}(k)}{x^{(0)}(k-1)}\left(k=2,3,\ldots,n\right) σ(k)=x(0)(k−1)x(0)(k)(k=2,3,…,n)
再根据预测发展系数 ( − a ^ ) (-\hat{a}) (−a^) 计算级比偏差和平均级比偏差
η ( k ) = ∣ 1 − 1 − 0.5 a ^ 1 + 0.5 a ^ 1 σ ( k ) ∣ , η ‾ = ∑ k = 2 n η ( k ) / ( n − 1 ) \eta(k)=\left|1-\frac{1-0.5\hat{a}}{1+0.5\hat{a}}\frac{1}{\sigma(k)}\right|,\:\overline{\eta}=\sum_{k=2}^{n}\eta(k)/(n-1) η(k)= 1−1+0.5a^1−0.5a^σ(k)1 ,η=k=2∑nη(k)/(n−1)
如果 η ˉ < 0.2 \bar{\eta}<0.2 ηˉ<0.2,则认为模型对原数据拟合达到一般要求; η ˉ < 0.1 \bar{\eta}<0.1 ηˉ<0.1,则认为模型对原数据拟合效果非常不错
clear;clc
year =[1995:1:2004]'; % 横坐标表示年份,写成列向量的形式
x0 = [174,179,183,189,207,234,220.5,256,270,285]'; %原始数据序列,写成列向量的形式
n = size(x0,1);
x1 = zeros(n,1);
for i = 1:n
x1(i) = sum(x0(1:i,1));
end
% 级比检验
rho = zeros(n,1);
for i = 2:n
rho(i) = x0(i) / x1(i-1);
end
figure(2)
plot(year(2:n,1),rho(2:n,1),'o-',[year(2),year(n)],[0.5,0.5],'-'); grid on;
text(year(end-1)+0.2,0.55,'临界线') % 在坐标(year(end-1)+0.2,0.55)上添加文本
set(gca,'xtick',year(2:1:end)) % 设置x轴横坐标的间隔为1
xlabel('年份'); ylabel('原始数据的光滑度'); % 给坐标轴加上标签
% 指标1:光滑比小于0.5的数据占比
num1 = sum(rho<0.5)/(n-1)
% 指标2:除去前两个时期外,光滑比小于0.5的数据占比
num2 = sum(rho(3:end)<0.5)/(n-3)
运行结果:
参考标准:指标1一般要大于60%, 指标2要大于90%,所以通过了级比检验。
function [result, x0_hat, relative_residuals, eta] = gm11(x0, predict_num)
n = size(x0,1);
x1 = cumsum(x0);
z1 = 0.5 * x1(2:end) + 0.5 * x1(1:n-1,1)
y = x0;
x = z1;
[b,bint,r,rint,stats]=regress(y, x); % 调用一元线性回归函数求解a和u
a = -b(1);
u = b(2);
x0_hat = zeros(n,1);
x0_hat(1) = x0(1);
for m = 1: n-1
x0_hat(m+1) = (1-exp(a))*(x0(1)-u/a)*exp(-a*m);
end
result = zeros(predict_num,1); % 初始化用来保存预测值的向量
for i = 1: predict_num
result(i) = (1-exp(a))*(x0(1)-u/a)*exp(-a*(n+i-1)); % 带入公式直接计算
end
% 计算绝对残差和相对残差
absolute_residuals = x0(2:end) - x0_hat(2:end); % 从第二项开始计算绝对残差,因为第一项是相同的
relative_residuals = abs(absolute_residuals) ./ x0(2:end); % 计算相对残差
% 计算级比和级比偏差
class_ratio = x0(2:end) ./ x0(1:end-1) ; % 计算级比
eta = abs(1-(1-0.5*a)/(1+0.5*a)*(1./class_ratio)); % 计算级比偏差
end
% 函数作用:使用传统的GM(1,1)模型对数据进行预测
% x0:要预测的原始数据
% predict_num: 向后预测的期数
% 输出变量
% result:预测值
% x0_hat:对原始数据的拟合值
% relative_residuals: 对模型进行评价时计算得到的相对残差
% eta: 对模型进行评价时计算得到的级比偏差
if num1 > 0.6 && num2 > 0.9
if n > 7 % 将数据分为训练组和试验组(根据原数据量大小n来取,n小于7则取最后两年为试验组,n大于7则取最后三年为试验组)
test_num = 3;
else
test_num = 2;
end
train_x0 = x0(1:end-test_num); % 训练数据
disp('训练数据是: ')
disp(mat2str(train_x0')) % mat2str可以将矩阵或者向量转换为字符串显示
test_x0 = x0(end-test_num+1:end); % 试验数据
disp('试验数据是: ')
disp(mat2str(test_x0'))
% 使用GM(1,1)模型对训练数据进行训练
disp('GM(1,1)模型预测')
result1 = gm11(train_x0, test_num); %预测后test_num期的结果
% 绘制对试验数据进行预测的图形
test_year = year(end-test_num+1:end); % 试验组对应的年份
figure(3)
plot(test_year,test_x0,'o-',test_year,result1,'*-'); grid on;
set(gca,'xtick',year(end-test_num+1): 1 :year(end))
legend('试验组的真实数据','GM(1,1)预测结果')
xlabel('年份'); ylabel('排污总量'); % 给坐标轴加上标签
predict_num = input('请输入你要往后面预测的期数: ');
% 计算使用传统GM模型的结果
[result, x0_hat, relative_residuals, eta] = gm11(x0, predict_num);
%% 绘制相对残差和级比偏差的图形
figure(4)
subplot(2,1,1) % 绘制子图(将图分块)
plot(year(2:end), relative_residuals,'*-'); grid on; % 原数据中的各时期和相对残差
legend('相对残差'); xlabel('年份');
set(gca,'xtick',year(2:1:end)) % 设置x轴横坐标的间隔为1
subplot(2,1,2)
plot(year(2:end), eta,'o-'); grid on; % 原数据中的各时期和级比偏差
legend('级比偏差'); xlabel('年份');
set(gca,'xtick',year(2:1:end))
%% 残差检验
average_relative_residuals = mean(relative_residuals); % 计算平均相对残差 mean函数用来均值
disp(strcat('平均相对残差为',num2str(average_relative_residuals)))
%% 级比偏差检验
average_eta = mean(eta); % 计算平均级比偏差
disp(strcat('平均级比偏差为',num2str(average_eta)))
%% 绘制最终的预测效果图
figure(5)
plot(year,x0,'-o', year,x0_hat,'-*m', year(end)+1:year(end)+predict_num,result,'-*b' ); grid on;
hold on;
plot([year(end),year(end)+1],[x0(end),result(1)],'-*b')
legend('原始数据','拟合数据','预测数据')
set(gca,'xtick',[year(1):1:year(end)+predict_num])
xlabel('年份'); ylabel('排污总量');
end
运行结果:
可以看出:平均相对残差为:0.025999 < 10 %
级比偏差为 0.047041 < 0.1 拟合效果非常不错