1.平滑指数的定义和作用
1. 平滑指数的定义
指数平滑法实际上是一种特殊的加权移动平均法。其特点是: 第一,指数平滑法进一步加强了观察期近期观察值对预测值的作用,对不同时间的观察值所赋予的权数不等,从而加大了近期观察值的权数,使预测值能够迅速反映市场实际的变化。权数之间按等比级数减少,此级数之首项为平滑常数a,公比为(1- a)。第二,指数平滑法对于观察值所赋予的权数有伸缩性,可以取不同的a 值以改变权数的变化速率。如a取小值,则权数变化较迅速,观察值的新近变化趋势较能迅速反映于指数移动平均值中。因此,运用指数平滑法,可以选择不同的a 值来调节时间序列观察值的均匀程度(即趋势变化的平稳程度).
系数α的确定
指数平滑法的计算中,关键是α的取值大小,但α的取值又容易受主观影响,因此合理确定α的取值方法十分重要,一般来说,如果数据波动较大,α值应取大一些,可以增加近期数据对预测结果的影响。如果数据波动平稳,α值应取小一些。理论界一般认为有以下方法可供选择:
1、当时间序列呈现较稳定的水平趋势时,应选较小的α值,一般可在0.05~0.20之间取值;
2、当时间序列有波动,但长期趋势变化不大时,可选稍大的α值,常在0.1~0.4之间取值;
3、当时间序列波动很大,长期趋势变化幅度较大,呈现明显且迅速的上升或下降趋势时,宜选择较大的α值,如可在0.6~0.8间选值,以使预测模型灵敏度高些,能迅速跟上数据的变化;
在实际应用中预测者应结合对预测对象的变化规律做出定性判断且计算预测误差,并要考虑到预测灵敏度和预测精度是相互矛盾的,必须给予二者一定的考虑,采用折中的α值.
初始值的确定
一般依据资料项数n的大小而定。
(1)当时间序列的数据n<20时,取前3项实际值的平均值为初始预测值;
(2) 当时间序列的数据n≥20时,一般用第一期的实际值作为初始预测值 [1] 。
2.平滑指数的作用
根据历史数据,通过平滑指数进行数据预测的工作
2.一次指数平滑
一次指数平滑一般应用于直线型数据,且一次指数平滑具有滞后性。
公式:
St----t期平滑值
xt-1--t-1期的实际值
a-----平滑系数
案例:
a=0.3
3.二次指数平滑
二次指数平滑一般也应用于直线型,但是效果会比一次指数平滑好很多,也就相当于加强版的一次指数平滑。
公式:
预测未来
期的值
的计算公式为:
案例:
a---0.3
4.三次指数平滑
三次指数平滑可以应用于抛物线型的数据,因为数据在二次平滑过后还是具有斜率,那么可以继续使用三次指数平滑。
公式:
预测未来期的值
的计算公式为:
其中:
案例:
a--0.3
5.代码实现
注意:平滑值不等于预测值
public class First {
public static void main(String[] args) {
List<Double> list = new LinkedList<Double>();
list.add(133d);
list.add(88d);
list.add(150d);
list.add(123d);
list.add(404d);
list.add(107d);
list.add(674d);
list.add(403d);
list.add(243d);
list.add(257d);
System.out.println(getFirst(list,0.3));
}
//一次指数平滑
public static Double getFirst(List<Double> list,Double module){
Double first=(list.get(0)+list.get(1)+list.get(2))/3;
double sum=0d;
for(int i=0;i<list.size();i++){
Double temp=list.get(i);
first=module*temp+(1-module)*first;
if(i<list.size()-1){
sum+=Math.abs(temp-first);
}
System.out.println("预测值:"+first+"误差值:"+(temp-first));
}
System.out.println("均方差:"+sum/(list.size()-1));
return first;
}
/**
* 二次指数平滑法求预测值 预测线性趋势
*
* @param list
* 基础数据集合
* @param year
* 未来第几期
* @param modulus
* 平滑系数
* @return 预测值
*/
private static Double getExpect(List<Double> list, int year, Double modulus) {
if (list.size() < 3 || modulus <= 0 || modulus >= 1) {
return null;
}
Double sum=0d;
Double modulusLeft = 1 - modulus;
// 一次预测 >20项默认第一个值为初始值
Double lastIndex = (list.get(0)+list.get(1)+list.get(2))/3;
// 二次预测 >20项默认第一个值为初始值
Double lastSecIndex = (list.get(0)+list.get(1)+list.get(2))/3;
for (Double data : list) {
// st1
lastIndex = modulus * data + modulusLeft * lastIndex;
// st2
lastSecIndex = modulus * lastIndex + modulusLeft * lastSecIndex;
// AT
Double a = 2 * lastIndex - lastSecIndex;
// BT
Double b = (modulus / modulusLeft) * (lastIndex - lastSecIndex);
sum+=Math.abs(data-(a + b * year));
System.out.println("预测值:"+(a + b * year)+"误差值:"+(data-(a + b * year)));
}
System.out.println("平均绝对误差:"+(sum/list.size()));
// AT
Double a = 2 * lastIndex - lastSecIndex;
// BT
Double b = (modulus / modulusLeft) * (lastIndex - lastSecIndex);
return a + b * year;
}
//三次指数平滑
public static Double getThridExpect(List<Double> list, int year, Double modulus) {
if (list.size() < 3 || modulus <= 0 || modulus >= 1) {
return null;
}
Double sum=0d;
Double modulusLeft = 1 - modulus;
// 一次预测 >20项默认第一个值为初始值
Double lastIndex = (list.get(0)+list.get(1)+list.get(2))/3;
// 二次预测 >20项默认第一个值为初始值
Double lastSecIndex = (list.get(0)+list.get(1)+list.get(2))/3;
// 三次预测 >20项默认第一个为初始值
Double lastThreadIndes = (list.get(0)+list.get(1)+list.get(2))/3;
for (Double data : list) {
// st1
lastIndex = modulus * data + modulusLeft * lastIndex;
// st2
lastSecIndex = modulus * lastIndex + modulusLeft * lastSecIndex;
// st3
lastThreadIndes = modulus * lastSecIndex + modulusLeft * lastThreadIndes;
// AT
Double a = 3 * lastIndex - 3 * lastSecIndex + lastThreadIndes;
// BT
Double b = (modulus /( 2 * (1 - modulus) * (1 - modulus))) * ((6 - 5 * modulus) * lastIndex
- 2 * (5 - 4 * modulus) * lastSecIndex + (4 - 3 * modulus) * lastThreadIndes);
// CT
Double c = ((modulus * modulus) / (2 * (1 - modulus) * (1 - modulus)))
* (lastIndex - 2 * lastSecIndex + lastThreadIndes);
sum+=Math.abs(data-(a + b * year + c * year * year));
System.out.println("预测值:"+(a + b * year + c * year * year)+"误差值:"+(data-(a + b * year + c * year * year)));
}
System.out.println("平均绝对误差:"+(sum/list.size()));
// AT
Double a = 3 * lastIndex - 3 * lastSecIndex + lastThreadIndes;
// BT
Double b = (modulus /( 2 * (1 - modulus) * (1 - modulus))) * ((6 - 5 * modulus) * lastIndex
- 2 * (5 - 4 * modulus) * lastSecIndex + (4 - 3 * modulus) * lastThreadIndes);
// CT
Double c = ((modulus * modulus) / (2 * (1 - modulus) * (1 - modulus)))
* (lastIndex - 2 * lastSecIndex + lastThreadIndes);
return a + b * year + c * year * year;
}
}
public class First {
public static void main(String[] args) {
List<Double> list = new LinkedList<Double>();
list.add(133d);
list.add(88d);
list.add(150d);
list.add(123d);
list.add(404d);
list.add(107d);
list.add(674d);
list.add(403d);
list.add(243d);
list.add(257d);
System.out.println(getFirst(list,0.3));
}
//一次指数平滑
public static Double getFirst(List<Double> list,Double module){
Double first=(list.get(0)+list.get(1)+list.get(2))/3;
double sum=0d;
for(int i=0;i<list.size();i++){
Double temp=list.get(i);
first=module*temp+(1-module)*first;
if(i<list.size()-1){
sum+=Math.abs(temp-first);
}
System.out.println("预测值:"+first+"误差值:"+(temp-first));
}
System.out.println("均方差:"+sum/(list.size()-1));
return first;
}
/**
* 二次指数平滑法求预测值 预测线性趋势
*
* @param list
* 基础数据集合
* @param year
* 未来第几期
* @param modulus
* 平滑系数
* @return 预测值
*/
private static Double getExpect(List<Double> list, int year, Double modulus) {
if (list.size() < 3 || modulus <= 0 || modulus >= 1) {
return null;
}
Double sum=0d;
Double modulusLeft = 1 - modulus;
// 一次预测 >20项默认第一个值为初始值
Double lastIndex = (list.get(0)+list.get(1)+list.get(2))/3;
// 二次预测 >20项默认第一个值为初始值
Double lastSecIndex = (list.get(0)+list.get(1)+list.get(2))/3;
for (Double data : list) {
// st1
lastIndex = modulus * data + modulusLeft * lastIndex;
// st2
lastSecIndex = modulus * lastIndex + modulusLeft * lastSecIndex;
// AT
Double a = 2 * lastIndex - lastSecIndex;
// BT
Double b = (modulus / modulusLeft) * (lastIndex - lastSecIndex);
sum+=Math.abs(data-(a + b * year));
System.out.println("预测值:"+(a + b * year)+"误差值:"+(data-(a + b * year)));
}
System.out.println("平均绝对误差:"+(sum/list.size()));
// AT
Double a = 2 * lastIndex - lastSecIndex;
// BT
Double b = (modulus / modulusLeft) * (lastIndex - lastSecIndex);
return a + b * year;
}
//三次指数平滑
public static Double getThridExpect(List<Double> list, int year, Double modulus) {
if (list.size() < 3 || modulus <= 0 || modulus >= 1) {
return null;
}
Double sum=0d;
Double modulusLeft = 1 - modulus;
// 一次预测 >20项默认第一个值为初始值
Double lastIndex = (list.get(0)+list.get(1)+list.get(2))/3;
// 二次预测 >20项默认第一个值为初始值
Double lastSecIndex = (list.get(0)+list.get(1)+list.get(2))/3;
// 三次预测 >20项默认第一个为初始值
Double lastThreadIndes = (list.get(0)+list.get(1)+list.get(2))/3;
for (Double data : list) {
// st1
lastIndex = modulus * data + modulusLeft * lastIndex;
// st2
lastSecIndex = modulus * lastIndex + modulusLeft * lastSecIndex;
// st3
lastThreadIndes = modulus * lastSecIndex + modulusLeft * lastThreadIndes;
// AT
Double a = 3 * lastIndex - 3 * lastSecIndex + lastThreadIndes;
// BT
Double b = (modulus /( 2 * (1 - modulus) * (1 - modulus))) * ((6 - 5 * modulus) * lastIndex
- 2 * (5 - 4 * modulus) * lastSecIndex + (4 - 3 * modulus) * lastThreadIndes);
// CT
Double c = ((modulus * modulus) / (2 * (1 - modulus) * (1 - modulus)))
* (lastIndex - 2 * lastSecIndex + lastThreadIndes);
sum+=Math.abs(data-(a + b * year + c * year * year));
System.out.println("预测值:"+(a + b * year + c * year * year)+"误差值:"+(data-(a + b * year + c * year * year)));
}
System.out.println("平均绝对误差:"+(sum/list.size()));
// AT
Double a = 3 * lastIndex - 3 * lastSecIndex + lastThreadIndes;
// BT
Double b = (modulus /( 2 * (1 - modulus) * (1 - modulus))) * ((6 - 5 * modulus) * lastIndex
- 2 * (5 - 4 * modulus) * lastSecIndex + (4 - 3 * modulus) * lastThreadIndes);
// CT
Double c = ((modulus * modulus) / (2 * (1 - modulus) * (1 - modulus)))
* (lastIndex - 2 * lastSecIndex + lastThreadIndes);
return a + b * year + c * year * year;
}
}