应用场景自己想,这里只讨论技术实现。
(1)什么是指数平滑算法?
一种通过实际值与上一次预估值进行比较计算就可以得出下一次预估值的中短期预测算法。 它的思想是利用近期的发展趋势,利用上一次的实际值和预测值之间的误差,来决定滑动指数a的权重大小,以此进行不断修正,来预测中短期未来的发展趋势。 滑动指数a 取值 范围是0~1之间。 a 越大,新数据占比越大,上一个预测值占比越小。 a 越小,新数据占比越小,上一个预测值占比越大。 在所有主流的预测算法中,指数滑动算法是运用最多,最广的算法。
(2)指数平滑算法跟其他一些简易平均法(算术平均/加权平均/几何平均/移动平均等)有什么区别?
上述简易平均算法无一例外都必须保留一定量的真实历史数据,这样会占一大部分内存用于存储。 上述简易平均算法只能大概计算一个平均数,无法有效体现升降趋势和不能准确抓住增量规律,无法通过近期的发展趋势动态修正。 上述简易平均算法受极端数据影响较大,且无法区分新旧数据的重要程度占比,混为一谈容易使得预测数据更容易受无用旧数据影响。
(3)指数平滑算法的优点和缺点?
优点: 1:能针对不同时间的数据分配不同的权重,根据上一次预测值动态评估调整修正。预测更加准确。 2:只需要保留上一次的预测值和实际值,节省了大量的内存空间,无需保存大量历史数据。 3:对平稳的升/降/水平发展趋势预测准确率非常高,预测模型能够自动识别数据模型变化自己调整。 缺点: 1:转折点处的预测不准确,所以针对波浪形的,上下浮动非常大,升降频率非常频繁的趋势预测会不准确。 2:长期预测不准,所以多用于中短期的预测。
概念背完,例子整起:
先看公式:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201105145326963.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3doaXRlQmVhckNsaW1i,size_16,color_FFFFFF,t_70#pic_center)
上源码:
@PostMapping("/singleExponentialSmoothingMethod")
public String singleExponentialSmoothingMethod(@RequestBody SingleSmoothingEntity singleSmoothingEntity){
/** 一次指数平滑公式:
* F(t+1)=a*Xt+(1-a)*Ft
*/
// (1)获取实际观察值列表和最后一次的预测值
List realParamList = singleSmoothingEntity.getRealDataList();
Double lastPredictParam = singleSmoothingEntity.getLastPredictParam();
// 定义结果集合类
Map resultMap = new HashMap();
List resultList = new ArrayList();
List gapList = new ArrayList();
Map gapMap = new HashMap();
DecimalFormat decimalFormat = new DecimalFormat("#.0");
// (2)平滑值区间 [1~10]
for (double a = 2; a
double smoothParam = a/10;
System.out.println("平滑指数:"+smoothParam+",实际值是:"
+ realData+",上次预测值是:"
+lastPredictParam+",误差为:"
+ decimalFormat.format(Math.abs(realData-lastPredictParam)));
// 将误差值装进list方便统计平均误差
gapList.add(Math.abs(realData - lastPredictParam));
lastPredictParam = smoothParam * realData + (1-smoothParam)*lastPredictParam;
// 保留一位小数
lastPredictParam = Double.valueOf(decimalFormat.format(lastPredictParam));
System.out.println("预测下次为:"+lastPredictParam);
}
// 计算误差的平均值
double totalGap = 0.0;
for (Double gap: gapList) {
totalGap = totalGap + gap;
}
System.out.println(gapList.size()+";"+totalGap);
gapMap.put(a,totalGap/(double) gapList.size());
// 每更换一个平滑值,预估值都要复位
lastPredictParam = singleSmoothingEntity.getLastPredictParam();
// 清空当前list装的误差值
gapList.clear();
}
return gapMap.toString();
}
SingleSmoothingEntity
public class SingleSmoothingEntity implements Serializable {
private static final long serialVersionUID = 1L;
private List realDataList;
private Double lastPredictParam;
public List getRealDataList() {
return realDataList;
}
public void setRealDataList(List realDataList) {
this.realDataList = realDataList;
}
public Double getLastPredictParam() {
return lastPredictParam;
}
public void setLastPredictParam(Double lastPredictParam) {
this.lastPredictParam = lastPredictParam;
}
}
测效果:
例一:
假设应用A数据量大且趋于平稳,波动较少,求下一期的预测值大约为多少,入参为: { “real_data_list”:[203.8,214.1,229.9,223.7,220.7,198.4,216.5,214.8,204.9,200.8,200,200,200], “last_predict_param”:203.8? } 获得滑动指数和每个滑动指数的平均误差: 也就是当 a = 0.7 时,误差最小,预测最准。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201105150022476.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3doaXRlQmVhckNsaW1i,size_16,color_FFFFFF,t_70#pic_center)
得到预测结果 Yt+1 = 200.1
例二:
假设应用A数据量较大且上升和下降趋势平稳单一,求未来一期的预测值: 入参: { “real_data_list”:[203.8,204.1,209.9,213.7,219.9,226.9,230,228.1,226.4,220.0,215,210,205.9,198.4], “last_predict_param”:203.8 } 获得滑动指数和每个滑动指数的平均误差: 可以看出当a =9.0时,误差值最小 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20201105150411672.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3doaXRlQmVhckNsaW1i,size_16,color_FFFFFF,t_70#pic_center)
以上例子,都是只能预测未来一期的结果,为什么呢?
因为受实际值的限制,所以一次指数平滑算法就是只能做未来一期的预测,在没有获得下一期的实际值前,没法再进行预测计算。如果要做往后几期的预测,只能使用二次和三次的指数平滑才能完成。
初始值,也就是上期预期值怎么确定?
如果发展变化趋势比较平稳的观察值,初始值可以直接用第一个数据(例如我的例子就是用了第一个数据)。如果变化趋势起伏较大,则要用平均值做初始值。(减少初始值对平滑值的影响)
|