
01
—
滑动平均认识
移动平均法是用一组最近的实际数据值来预测未来一期或几期内公司产品的需求量、公司产能等的一种常用方法。移动平均法适用于即期预测。当产品需求既不快速增长也不快速下降,且不存在季节性因素时,移动平均法能有效地消除预测中的随机波动,是非常有用的。移动平均法根据预测时使用的各元素的权重不同
移动平均法是一种简单平滑预测技术,它的基本思想是:根据时间序列资料、逐项推移,依次计算包含一定项数的序时平均值,以反映长期趋势的方法。因此,当时间序列的数值由于受周期变动和随机波动的影响,起伏较大,不易显示出事件的发展趋势时,使用移动平均法可以消除这些因素的影响,显示出事件的发展方向与趋势(即趋势线),然后依趋势线分析预测序列的长期趋势。
移动平均法的种类
移动平均法可以分为:简单移动平均和加权移动平均。
(1)简单移动平均法
简单移动平均的各元素的权重都相等。简单的移动平均的计算公式如下:Ft=(At-1+At-2+At-3+…+At-n)/n式中,·Ft–对下一期的预测值;·n–移动平均的时期个数;·At-1–前期实际值;·At-2,At-3和At-n分别表示前两期、前三期直至前n期的实际值。
(2)加权移动平均法
加权移动平均给固定跨越期限内的每个变量值以不同的权重。其原理是:历史各期产品需求的数据信息对预测未来期内的需求量的作用是不一样的。除了以n为周期的周期性变化外,远离目标期的变量值的影响力相对较低,故应给予较低的权重。加权移动平均法的计算公式如下:
Ft=w1At-1+w2At-2+w3At-3+…+wnAt-n式中
·w1–第t-1期实际销售额的权重;
·w2–第t-2期实际销售额的权重;
·wn–第t-n期实际销售额的权
·n–预测的时期数;w1+ w2+…+ wn=1
在运用加权平均法时,权重的选择是一个应该注意的问题。经验法和试算法是选择权重的最简单的方法。一般而言,最近期的数据最能预示未来的情况,因而权重应大些。例如,根据前一个月的利润和生产能力比起根据前几个月能更好的估测下个月的利润和生产能力。但是,如果数据是季节性的,则权重也应是季节性的。
移动平均法的优缺点
使用移动平均法进行预测能平滑掉需求的突然波动对预测结果的影响。但移动平均法运用时也存在着如下问题:
加大移动平均法的期数(即加大n值)会使平滑波动效果更好,但会使预测值对数据实际变动更不敏感;
移动平均值并不能总是很好地反映出趋势。由于是平均值,预测值总是停留在过去的水平上而无法预计会导致将来更高或更低的波动;
移动平均法要由大量的过去数据的记录。

02
—
滑动平均Java工具类实现
剩余点个数=窗口长度-1=需要补数的个数
如果不考虑剩余点则最终返回结果数组的长度=原始数组长度-窗口长度+1
import java.util.Arrays;import static org.apache.commons.math.stat.StatUtils.mean;/*** 滑动平均计算* Created by dandan.* 属性解释:* movWindowSize:移动平均计算的滑动窗口* movLeaveTemp:临时数组记录最后得不到均值处理的点* movResBuff:输出最终结果数组* movResBuffLen:输出最终结果数组长度* inputBuff:输入数据数组* winArray:滑动窗口所形成的数组* winArrayLen:滑动窗口所形成的数组长度* tempCal:原始数组+插值后的扩容数组*/public class movingAverage {private static final int WINDOWS = 5;private int movWindowSize = WINDOWS; //窗口大小public movingAverage() {}public movingAverage(int size) {movWindowSize = size;}// 均值滤波方法,输入一个inputBuff数组,返回一个movResBuff数组,两者下标不一样,所以定义不同的下标,inputBuff的下标为i,movResBuff的下标为movResBuffLen.// 同理,临时的winArray数组下表为winArrayLenpublic double[] movingAverageCal(double[] inputBuff) {int movResBuffLen = 0;int winArrayLen = 0;//定义返回结果数组double[] movResBuff = new double[inputBuff.length];//定义窗口数组double[] winArray = new double[movWindowSize];//求整体输入序列的平均值作为一个插值点double replace = mean(inputBuff);//对原始数组扩容,将插值点放进去.剩余点个数是窗口大小-1.需要补充值的个数等于剩余点的个数double[] tempCal = new double[inputBuff.length + movWindowSize-1];//拷贝原始数组到临时计算数组System.arraycopy(inputBuff, 0, tempCal, 0, inputBuff.length);//将平均值插入进去for (int m = inputBuff.length; m <tempCal.length ; m++) {tempCal[m]=replace;}//开始计算for (int i = 0; i < tempCal.length; i++) {if ((i + movWindowSize) > tempCal.length) {break;} else {for (int j = i; j < (movWindowSize + i); j++) {winArray[winArrayLen] = tempCal[j];winArrayLen++;}movResBuff[movResBuffLen] = mean(winArray);movResBuffLen++;winArrayLen = 0;}}return movResBuff;}public static void main(String[] args) {double[] inputBuff={670,680,690,680,700,720,730,740,740,760,780,790};movingAverage movingAverage = new movingAverage();double[] filter = movingAverage.movingAverageCal(inputBuff);System.out.println(filter.length);System.out.println(Arrays.toString(filter));System.out.println(mean(filter));}}
03
—
Hive UDF 实现
在上述返回值的基础上再次平均求得特征值
import org.apache.hadoop.hive.ql.exec.UDF;import java.util.ArrayList;import java.util.List;import static org.apache.commons.math.stat.StatUtils.mean;public class movingAverageFeaCal extends UDF {public static void main(String[] args) {String num_all = "3.1002," +"3.0984," +"3.147," +"3.197," +"3.1002," +"3.1002," +"3.0854," +"3.0982," +"3.12," +"3.09," +"3.a091";movingAverageFeaCal movingAverageFeaCal = new movingAverageFeaCal();Double evaluate = movingAverageFeaCal.evaluate(num_all, 3);System.out.println(evaluate);}public Double evaluate(String num_all,int windowSize) {if (num_all == null || num_all.isEmpty()) {return null;//参数不全,不需要计算}String[] numArr = num_all.split(",");List<Double> list = new ArrayList();double num = 0;if (numArr.length > 0) {for (String aNumArr : numArr) {// boolean flag = Utils.isNumber(numArr[i]);if (aNumArr != null && !aNumArr.isEmpty() && !aNumArr.equals("null") && !aNumArr.equals("NULL") && Utils.isNumber(aNumArr)) {num = Double.parseDouble(aNumArr);list.add(num);}}// Double[] arr1 = list.toArray(new Double[list.size()]);double[] inputBuff= list.stream().mapToDouble(i -> i).toArray();movingAverage movingAverage = new movingAverage(windowSize);double[] feaArr = movingAverage.movingAverageCal(inputBuff);return mean(feaArr);} else {return null;}}}
04
—
小结
本文介绍了滑动平均法,包括其认识、种类(简单移动平均和加权移动平均)、优缺点,还讨论了Java实现滑动平均的细节,并提到了Hive UDF函数在计算过程中的作用。

往期精彩
数仓建模:如何有效构建DWB/DWM层?| 基于案例实战分析




