二次指数平滑法实现数据预测-java

    前段时间做了使用二次指数平滑法实现数据预测的,现整理一下。

公式:

/**
     * 二次指数平滑预测方法
     * @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;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值