應上頭的要求,須要實現如下指數平滑進行資源調度負載的預測,那就是用我最喜歡的Java作一下吧。java
引用《計量經濟學導論》的一句話:時間序列數據區別於橫截面數據的一個明顯特色是,時間序列數據集是按照時間順序排列的。python
顯然,橫截面數據被視爲隨機的結果,也就是說在整體中隨機抽取樣本。時間序列數據和橫截面數據區別較爲微妙,雖然它也知足隨機性,可是這個序列標有時間腳標,依照時間有序,而不可讓時間隨機排列致使錯亂,咱們不能讓時間逆轉從新開始這個過程。對於這樣的序列咱們稱之爲隨機過程,或者時間序列過程。數組
對於時間序列,常常研究的一個問題就是預測,而指數平滑法是很是常見也經常使用的方法之一。這裏對於二次指數平滑進行Java的實現(一次指數平滑包含在二次指數平滑以內)。其原理參照: https://cloud.tencent.com/developer/article/1058557 。這裏就再也不贅述。函數
數據也是參照我國1981年至1983年度平板玻璃月產量數據,如下文件保存爲data2.txtthis
我國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類型,爲了便於讀取,對於以上數據定義行數據類spa
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數組3d
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; } }
而後定義時間序列分析類,其實就是一個函數code
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"); } } }
執行結果:blog
事實上還能夠使用Java進行時間序列圖像繪製,畢竟Java跑完python或matlab繪圖還挺麻煩,Java也是能夠實現的,只不過爲了方便須要寫一個龐大的API,往後閒下來再寫一篇博客細說。資源