一、实验目的
数据:自选或train.csv
-
实现移动平均;
a) 一次移动平均,取多个n值,计算标准差;
b) 二次移动平均,计算参数a,b,进行预测; -
实现指数平滑。
a) 一次指数平滑,取多个a值;
b) 二次指数平滑(可选);
二、实验平台
Python 3.7
三、实验内容与结果:
3.1题目分析
实现移动平均分析:
一次移动平均的公式:
标准差的公式即为MSE公式开根号:
二次移动平均公式:
二次移动平均预测法的预测模型(解析过程中默认了t为最后一期数据,T为1):
a和b的计算公式:
实现指数平滑分析:
一次指数平滑公式:
二次指数平滑公式:
预测模型以及a和b的值:
依题意得,就是读入数据,然后带入公式就行
3.2实验代码:
# -*- codeing =utf-8 -*-
# @Time : 2021/4/15 15:13
# @Author : ArLin
# @File : demo2.py
# @Software: PyCharm
import csv
from collections import deque
import numpy
import numpy as np
#读取csv文件
def ReadCsvFile(path):
File = open(path, 'r')
f = csv.reader(File)
i = 0
data = []
for row in f:
if i > 0:#去头处理
data.append(int(row[2]))
i = i + 1
return data
def MovingAverage(data,n): #移动平均法
ForecastN=len(data)+1
d1=deque()
P_data=[]
for i in data:
d1.appendleft(i)
if len(d1) == n:
P_data.append(np.round(sum(d1) / len(d1),1))
d1.pop()
return P_data
#计算标准差
def Forecast_Standard_Deviation(data,Pdata,n):
s = []
sn = 0
for index in range(len(Pdata) - 1):
s1 = (Pdata[index] - data[n + index]) ** 2 #标准差公式
s.append(np.round(s1, 1))
y =int((sum(s) / len(s)) ** 0.5)
print('N为:',n,'时,一次移动平均计算出的标准差:',y)
return y
#计算A和B的值和预测值
def CountAandB(P1data,P2data,n):
for index in range(len(P2data)):
a1=2*P1data[index+n-1]-P2data[index] #a的公式
b1=(2/(n-1))*(P1data[index+n-1]-P2data[index])#b的公式
if index==len(P2data)-1:
a11=int(a1)
b11=int(b1)
F = a11 + b11#默认T为1的情况计算F
print('N的值为:',n,'时,a的值为:',a11,'b的值为:',b11,'二次移动平均预测法的预测值为:',F)
return a11,b11
#一次,二次指数平滑值
def One_and_TwoOrderExponentialSmoothing(data,a):
s1=[]
s2=[]
s0 = (data[0] + data[1] + data[2]) / 3
s1.append(np.round(s0, 2))
s2.append(np.round(s0, 2))
for index in range(len(data)):
si1=a*data[index]+(1-a)*s1[index]
s1.append(np.round(si1, 2))
si2=a*s1[index+1]+(1-a)*s2[index]
s2.append(np.round(si2, 2))
print('当a为',np.round(a, 1), '时,一次指数平滑值为:', s1[len(data)])
return s1,s2
#预测模型以及a和b的值
def ABExponentialSmoothing(s1,s2,A):
for index in range(len(s2)):
a1 = 2 * s1[index]-s2[index]
b1 = (A/(1-A))*(s1[index]-s2[index])
if index == len(s2)-1:
a11= np.round(a1, 2)
b11= np.round(b1, 2)
F = a11+b11
print('A的值为:',np.round(A, 1), '时,a的值为:', a11, 'b的值为:', b11, '二次指数平滑值的预测值为:', np.round(F, 2))
return a11, b11
def allMovingAverage(data,n):
P1_data = MovingAverage(data, n)
P2_data = MovingAverage(P1_data, n)
Forecast_Standard_Deviation(data, P1_data, n)
CountAandB(P1_data, P2_data, n)
if __name__ =='__main__':
path='train.csv'
data=ReadCsvFile(path)
for i in range(2,18):
allMovingAverage(data,i)
for i in numpy.arange(0.1, 1, 0.1):
s=One_and_TwoOrderExponentialSmoothing(data, i)
ABExponentialSmoothing(s[0],s[1],i)
3.3结果与分析:
结果截图:
移动平均结果截图:
指数平滑实验结果截图:
实验结果分析:
从移动平均结果截图中我们可以看出,
在选取从2-20的多个n值中,
当n=2时,一次移动平均计算出的标准差最小,为46。
而从指数平滑实验结果截图中我们可以看出在选取0.1-1的多个a值中
平滑系数a对预测精度影响很大, a越大(接近于1),表示模型越来越重视近期数据的作用,对过程的变化反映越快;
a越小,表示模型越重视离现时更远的历史数据的作用,对过程变化的反映越迟钝。
3.4实验总结
出现的问题与解决方法:
问题1:
读取csv的时候报错
<_csv.reader object at 0x0000026E7F21BCE0>
原代码:
File=open(r'train.csv','r')
f=csv.reader(File)
print(f)
解决方法:
因为csv.reader返回的是一个迭代类型,索引应该用循环来打印信息才行
修改后的代码:
File=open(r'train.csv','r')
f=csv.reader(File)
#print(f)
for row in f:
print(row)
问题2:
刚开始在保留小数位的时候我采用的是’%.xf’方法后面发现这个貌似只能在print中使用,达不到我的预期,我就又使用了format函数但是导致保留进列表的数据是字符串的形式,就导致多了一步操作
解决方法:
最后我采用了round()函数,发现是最省时省力的了。
问题3:
其实一开始我写的预测模式的t和T是可以自定义的,但是由于数据量非常大,处理起来就会很麻烦,很繁琐
解决方法:
虽然我实现了这个算法函数,但是经过和同学沟通后还是决定把t定为最后一位数据,T为1
知识点总结:
- 移动平均:
以计算算术平均数为基础的算法,适用对象为: 一组随时间变化而波动的数据, 时间序列变动不太剧列,较平稳。方法是每次在时间序列上移动一步求平均值,作用是能消除季节性变动、周期性变动与随机变动的影响, 突出长期趋势 - 指数平滑:
初始值的确定:
时间序列原始值较多, a较大时可取s0(1)=x1,s0(2)=s0(1)
数据点不多,初始值对预测精度影响较大时,可取开始几个观测值的算术平均值、加权平均值做初始值。
a的影响:
平滑系数a对预测精度影响很大, a越大(接近于1),表示模型越来越重视近期数据的作用,对过程的变化反映越快;a越小,表示模型越重视离现时更远的历史数据的作用,对过程变化的反映越迟钝。
a的取值经验(通常0.01<a <0.3):
初始值不可靠时,a倾向取大
原始数据波动大时, a倾向取大,反之亦反
3. python保留小数位的三种实现方法
format函数
'%.xf’方法
round()函数
4. dequed队列
个人总结:
本次的实验比起之前更有亲和感吧,可能是因为是从之前写的纸质版作业到现在的代码实现,有了从纸质到电子版的突破,在实验过程中其实也是按部就班的自己先算一遍,然后把公式变成代码,一遍遍测试,过程中遇到的一些问题也通过debug解决了,而且发现编写代码后,重点留下的是算法思想,而繁琐的工作由计算机完成了,或许这也是编程的魅力吧。老师之前一直有说可以让生活中融入python,慢慢的现在的作业我也有在开始用编程直接实现,省了很多力气吧,但是由于目前的基础原因,其实有很多不懂的知识点还是面向百度,但是学习呢应该就是这样一个积累的过程吧。不积硅步,无以至千里。