前段时间做了使用二次指数平滑法实现数据预测的,现整理一下。
公式:
/**
* 二次指数平滑预测方法
* @param data 真实数据
* @param t 预测期数
* @param a 平滑系数
* @return
*/
public static double getPrediction(List<Double> data, int t,double a) {
List<Double> S1 = new ArrayList<Double>();//存放第一次预测值
List<Double> S2 = new ArrayList<Double>();//存放第二次预测值
double st = 0.0;//初始预测值
double at = 0.0;
double bt = 0.0;
double xt = 0.0;//本期预测值
int size=data.size();//实际数据总数
if (size < 20){
double s1 = data.get(0)+data.get(1)+data.get(2);//真实值前三项和
st = s1 / 3;
}else{
st = data.get(0);
}
//第一次预测
for (int k = 0; k < size; k++) {
if (k == 0){
S1.add(a * data.get(k) + (1 - a) * st);
}else{
S1.add(a * data.get(k) + (1 - a) * S1.get(k - 1));
}
}
//第二次预测
for (int l = 0; l < size; l++) {
if (l == 0)
S2.add(a * S1.get(l) + (1 - a) * st);
else
S2.add(a * S1.get(l) + (1 - a) * S2.get(l - 1));
}
at = S1.get(S1.size() - 1) * 2 - S2.get(S2.size() - 1);
bt = a / (1 - a) * (S1.get(S1.size() - 1) - S2.get(S2.size() - 1));
xt = at + bt * t;
return xt;
}
/**
* 求平滑系数
* 误差平方平均值最小的为最优系数
* @param data 真实参考数据
* @return 最优平滑系数
*/
public static double getA2(List<Double> data){
double xs=0.0;//指数平滑系数
Map map=new HashMap();//key平滑系数 value误差平均平方和
List<Double> S2_1 = new ArrayList<Double>();
double errorTotal=0.0;//所有误差平方和
double st = 0.0;//初始预测值
int size = data.size();
//数据量大于20时初始数据取第一个,小于20取前三项平均值
if (size < 20){
double s1 = data.get(0)+data.get(1)+data.get(2);//真实值前三项和
st = s1 / 3.0;
}else{
st = data.get(0);
}
st=Double.valueOf(df.format(st));
for(double a=0.1;a<1;a+=0.1){ //平滑系数范围0.1~0.9
a=Double.valueOf(adf.format(a));
for (int k = 0; k < size; k++) {
double error1=0.0;
double yc=0.0;
if (k == 0){
yc=a * data.get(k) + (1 - a) * st;//预测值
}else{
yc=a * data.get(k) + (1 - a) * S2_1.get(k - 1);//预测值
}
S2_1.add(yc);
error1=data.get(k)-yc;//误差=实际值-预测值
errorTotal=errorTotal+(error1*error1); //误差平方和
}
map.put(a+"",errorTotal);
errorTotal=0.0;
S2_1 = new ArrayList<Double>();
}
xs=getOptimalA(map);;
return xs;
}
/**
* 排序后求最优平滑系数
* @param map key-平滑系数 value-误差值
* @return 最优平滑系数
*/
public static double getOptimalA(Map map){
double a=0.0;
//根据误差值value升序排序
List<Map.Entry<String, Double>> orderMap = new ArrayList<Map.Entry<String, Double>>(map.entrySet());
Collections.sort(orderMap, new Comparator<Map.Entry<String, Double>>() {
@Override
public int compare(Entry<String, Double> map1, Entry<String, Double> map2) {
double result = map1.getValue() - map2.getValue();
if (result > 0)
return 1;
else if (result == 0)
return 0;
else
return -1;
}
});
Entry<String, Double> entry = orderMap.get(0);
System.out.println("最优权重a="+entry.getKey());
a=Double.valueOf(entry.getKey());
return a;
}