实现趋势外推法
:一次、二次、三次,指数曲线法;
步骤
1.收集研究对象的动态数列(自选);
2.画数据点分布图,判断近似曲线;
3.计算差分,确定曲线方程;
4.求曲线参数;
概念
代码
# -*- coding=utf-8 -*-
# name: nan chen
# date: 2021/4/22 14:22
import csv
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import numpy as np
font = FontProperties(fname=r"C:\\Windows\\Fonts\\STKAITI.TTF", size=7)
# 计算差分 选取相应模型
def count_difference_choose(t_array, y_array):
# 计算差分
y1 = []
y2 = []
yy = []
for i in range(1, len(y_array)):
y1.append(round(y_array[i] - y_array[i - 1], 2))
for i in range(1, len(y1)):
y2.append(round((y1[i] - y1[i - 1]), 2))
for i in range(1, len(y_array)):
yy.append(round((y_array[i] / y_array[i - 1]), 2))
'''
print("一阶差分为:", y1)
print("二阶差分为:", y2)
print("一阶差比率为:", yy)
'''
plt.figure(2)
plt.plot(y1, '--', label="一阶差分")
plt.plot(y2, '-.', label="二阶差分")
plt.plot(yy, label="一阶差比率")
plt.legend(prop=font)
std1 = np.std(y1)
std2 = np.std(y2)
std3 = np.std(yy)
print("一阶差分的方差为:", std1)
print("二阶差分的方差为:", std2)
print("一阶差比率的方差为:", std3)
if std1 <= std2 and std1 <= std3:
linear_trend(t_array, y_array)
elif std2 <= std1 and std2 <= std3:
Conic_trend(t_array, y_array)
elif std3 <= std2 and std3 <= std1:
index_trend(t_array, y_array)
# 一次
def linear_trend(t_array, y_array):
y_avg = np.mean(y_array)
b = np.sum(t_array * y_array) / np.sum(t_array ** 2)
a = y_avg
predict = a + b * (t_array[-1] + 1)
print(predict)
# 二次
def Conic_trend(t_array, y_array):
a = (np.sum(t_array ** 4) * np.sum(y_array) - np.sum(t_array ** 2) * np.sum((t_array ** 2) * y_array)) / (
len(t_array) * np.sum(t_array ** 4) - (np.sum(t_array ** 2)) ** 2)
b = np.sum(t_array * y_array) / np.sum(t_array ** 2)
c = len(t_array) * np.sum((t_array ** 2) * y_array) - np.sum(y_array) * np.sum(t_array ** 2) / (
len(t_array) * np.sum(t_array ** 4) - (np.sum(t_array ** 2)) ** 2)
predict = a + b + c * (t_array[-1] + 1)
# 指数
def index_trend(t_array, y_array):
a = np.sum(np.log10(y_array)) / len(y_array)
b = np.sum(t_array * np.log10(y_array)) / (np.sum(t_array ** 2))
A = 10 ** a
B = 10 ** b
predict = A * (B ** (t_array[-1] + 3))
predicts = []
for i in t_array:
predicts.append(A * (B ** i))
plt.figure(3)
plt.plot(predicts, label="预测值")
plt.plot(price, '.', label="实际值")
plt.legend(prop=font)
plt.show()
print("下一年金价的预测值为:", predict)
if __name__ == '__main__':
# 读取数据文件
with open(r"D:\Downloads\gold_annual_price.csv", encoding="utf-8") as f:
reader = csv.reader(f)
header_row = next(reader)
date = []
price = []
for row in reader:
date.append(row[0])
price.append(round(float(row[1]), 2))
plt.figure(1)
plt.plot(price, '.')
n = int(len(date) / 2)
t_array = np.array(range(-1 * n, n + 1))
y_array = np.array(price)
'''
t_array = np.array(range(-7, 8))
y_array = np.array(
[121.12, 127.87, 139.12, 160.69, 189.26, 255.61, 268.25, 302.36, 348.63,408.86, 438.6, 543.85, 575.62, 703.26,
816.22])
'''
count_difference_choose(t_array, y_array)
结果及分析
-
数据的散点图
-
差分:一阶、二阶、一阶差比率
-
绘图观察一阶、二阶、三阶、一阶差比率
-
计算差分的方程,选择相应的曲线方程
-
预测结果
-
预测值与真实值对比
结果分析:
- 本次实验选取的数据集为1951年-2021年历史每一年度的国际金价。绘制散点图可以看出,大致呈指数分布,猜测应该使用指数曲线模型。
- 通过观察一阶、二阶、一阶差比率可以看出一阶差比率大致相等,而一阶差分及二阶差分的波动幅度则特别大,验证了我们刚刚的观察应选取指数曲线模型。
- 通过公式计算参数,确定参数方程,可以求得预测值为2048.19