時間序列數據的定義,讀取與指數平滑(Java)


  應上頭的要求,需要實現以下指數平滑進行資源調度負載的預測,那就是用我最喜歡的Java做一下吧。

  引用《計量經濟學導論》的一句話:時間序列數據區別於橫截面數據的一個明顯特點是,時間序列數據集是按照時間順序排列的。

  顯然,橫截面數據被視為隨機的結果,也就是說在總體中隨機抽取樣本。時間序列數據和橫截面數據區別較為微妙,雖然它也滿足隨機性,但是這個序列標有時間腳標,依照時間有序,而不可以讓時間隨機排列導致錯亂,我們不能讓時間逆轉重新開始這個過程。對於這樣的序列我們稱之為隨機過程,或者時間序列過程。

  對於時間序列,經常研究的一個問題就是預測,而指數平滑法是非常常見也常用的方法之一。這里對於二次指數平滑進行Java的實現(一次指數平滑包含在二次指數平滑之內)。其原理參照: https://cloud.tencent.com/developer/article/1058557 。這里就不再贅述。

 

數據也是參照我國1981年至1983年度平板玻璃月產量數據,以下文件保存為data2.txt

我國1981年至1983年度平板玻璃月產量數據
1,240.3
2,222.8
3,243.1
4,222.2
5,222.6
6,218.7
7,234.5
8,248.6
9,261
10,275.3
11,269.4
12,291.2
13,301.9
14,285.5
15,286.6
16,260.5
17,298.5
18,291.8
19,267.3
20,277.9
21,303.5
22,313.3
23,327.6
24,338.3
25,340.37
26,318.51
27,336.85
28,326.64
29,342.9
30,337.53
31,320.09
32,332.17
33,344.01
34,335.79
35,350.67
36,367.37

對於以上數據,時間是int類型,而產量是double類型,為了便於讀取,對於以上數據定義行數據類

package timeSeries;

public class RowData {

    private int time;
    private double value;
    
    public RowData() {
        // TODO Auto-generated constructor stub
    }

    public RowData(int time, double value) {
        super();
        this.time = time;
        this.value = value;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

    public double getValue() {
        return value;
    }

    public void setValue(double value) {
        this.value = value;
    }

}

然后定義文件讀取類,讀取所得數據為RowData數組

package utilFile;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import timeSeries.RowData;

public class FileOpts {

    public static ArrayList<RowData> loadTxt(String dataPath, boolean ishead) {
        File file = new File(dataPath);
        FileReader fr;
        ArrayList<RowData> datas = new ArrayList<RowData>();
        try {
            fr = new FileReader(file);
            BufferedReader br = new BufferedReader(fr);
            String line = "";
            String[] splitdata;
            if (ishead) {
                br.readLine();
            }
            while ((line = br.readLine()) != null) {
                splitdata = line.split(",");
                datas.add(new RowData(Integer.parseInt(splitdata[0]), Double.parseDouble(splitdata[1])));
            }
            br.close();
            fr.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return datas;
    }

}

然后定義時間序列分析類,其實就是一個函數

package timeSeries;

import java.util.ArrayList;

import java.util.Iterator;


public class ExponentialSmoothing2 {

    public static double[][] expSmoothOrder2(int[] time, double[] values, double alpha, int preNum) {
        int len = time.length;
        // 返回一個匯總表
        double[][] result = new double[len + preNum][7];
        // 第一列時間,第二列實際觀察值
        for (int i = 0; i < len; i++) {
            result[i][0] = time[i];
            result[i][1] = values[i];
        }
    
        result[0][2] = values[0];
        result[0][3] = result[0][2];
    
        // 第三列一次指數平滑值,第四列二次指數平滑值
        // S1, S2 2, 3
        for (int i = 1; i < len; i++) {
            result[i][2] = alpha*values[i] + (1-alpha)*result[i-1][2];
            result[i][3] = alpha*result[i][2] + (1-alpha)*result[i-1][3];
        }
    
        // 第五列a,第六列b
        // a, b 4, 5
        for (int i = 1; i < len; i++) {
            result[i][4] = 2*result[i][2] - result[i][3];
            result[i][5] = alpha/(1-alpha) * (result[i][2] - result[i][3]);
        }
        // 第七列預測值F
        // F 6
        for (int i = 1; i < len; i++) {
            result[i+preNum][6] = result[i][4] + result[i][5] * preNum;
        }
        return result;
    }
    
    public static void main(String[] args) {
        // 獲取數據
        ArrayList<RowData> data = utilFile.FileOpts.loadTxt("src/timeSeries/data2.txt", true);
        int len = data.size();
        int[] time = new int[len];
        double[] values = new double[len];
        Iterator<RowData> it = data.iterator();
        int index = 0;
        while (it.hasNext()) {
            RowData rowData = (RowData) it.next();
            time[index] = rowData.getTime();
            values[index] = rowData.getValue();
            index++;
        }
        // -------------------數據准備完畢---------------
        
//        System.out.println(Arrays.toString(time));
//        System.out.println(Arrays.toString(values));
        // ------------------二次指數平滑---------------------
        double[][] pre2= expSmoothOrder2(time, values, 0.5, 1);
        System.out.printf("%6s, %6s, %6s, %6s, %6s, %6s, %6s\n", "time", "y", "s1", "s2", "a", "b", "F");
        for (int i = 0; i < values.length; i++) {
            System.out.printf("%6.2f, %6.2f, %6.2f, %6.2f, %6.2f, %6.2f, %6.2f \n", pre2[i][0], pre2[i][1], pre2[i][2],
                    pre2[i][3], pre2[i][4], pre2[i][5], pre2[i][6]);
        }
//        System.out.printf("%6d, %6d, %6d, %6d, %6d, %6d, %6.2f \n", 37, 0, 0, 0, 0, 0, pre2[values.length][3]);
//        System.out.printf("%6d, %6d, %6d, %6d, %6d, %6d, %6.2f \n", 38, 0, 0, 0, 0, 0, pre2[35][1] + pre2[35][2] * 2);
        // 誤差分析
        double MSE = 0;
        double MAPE = 0;
        double temp;
//        System.out.println("pre2.length = "+pre2.length);
        for (int i = 2; i < pre2.length-1; i++) {
            MSE += (pre2[i][1]-pre2[i][6])*(pre2[i][1]-pre2[i][6])/(pre2.length-2);
            temp = (pre2[i][1]-pre2[i][6])/pre2[i][1];
            if (temp < 0) {
                MAPE -= temp/(pre2.length-2);
            }else {
                MAPE += temp/(pre2.length-2);
            }
//            System.out.printf("iter: %d, y = %6.2f, F = %6.2f, MSE = %6.2f, MAPE = %6.5f\n", i, pre2[i][1], pre2[i][6], MSE, MAPE);
        }
        System.out.printf("MSE = %6.2f, MAPE = %6.5f\n", MSE, MAPE);
        if (MAPE < 0.05) {
            System.out.println("百分誤差小於0.05,預測精度較高");
        }else {
            System.out.println("預測誤差超過了0.05");
        }
    }


}

執行結果:

   其他時間序列模型還有溫特線性和季節性指數平滑法、ARIMA和GARCH等等,可見於《數學建模》或《計量經濟學》。其實處理時間序列,用SPSS或R語言是很方便的,或者Matlab。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM