三次指数平滑算法+java_指数平滑法
时间序列分解
⼤量时间序列的观测样本表现出趋势性、季节性和随机性,或者三者中的其⼀或其⼆。于是,我们认为每个时间序列,都可以分为三个部分的叠加
其中,T是趋势项,S是季节项,R是随机项。
上述公式表现了趋势项和季节项是累加的,实际应⽤场景中,趋势项和季节项可能是累乘的,时间序列可以分解为如下公式
实际应⽤中,随机项R的期望为0,没有规律,并且绝对值不⼤。所以在应⽤场景中我们往往省略掉R,R称作噪声。预测公式如下
或
⼀次指数平滑法
线性回归算法中,每个经验点的权重是⼀致的,即很早以前的经验数据也可能对预测数据有较⼤的影响。很多实际场景中,未来⼀段时间的趋势可能和在最近⼀段时间的趋势关系更加紧密。⽐如⼩明去年数学考试成绩⼀直不及格,今年连续多次考试90多分,预测⼩明下⼀次数学考试的成绩,情理上90多分的可能性更⾼。采⽤传统的线性回归算法,预测结果可能是70多分。
指数平滑法认为越⽼的经验数据对趋势的影响越⼩。我们假定时间t的观测值为y(t),时间t的预测值为S(t),则时间t+1的预测值S(t+1)为
a的取值范围(0, 1),a越⼤,最近时间点的观测值对预测值的影响越⼤。
假设我们有t个经验数据,根据上述⼀次指数平滑公式,预测值S(t + n) = S(t + 1),预测值不具备趋势。
⼆次指数平滑
我们对⼀次指数平滑值再进⾏指数平滑,可以获得趋势。⼆次指数平滑法的预测模型为:
式中:
分别为时间t和时间t - 1的⼆次指数平滑值。
三次指数平滑
⼆次指数模型是线性的,对于⾮线性趋势预测我们可以使⽤三次指数平滑法。公式如下
Holt-Winters算法questionable
对于具有周期性的趋势预测,我们可以使⽤Holt-Winters算法。累乘性Holt-Winters公式如下
其中,alpha,beta,gamma取值范围为(0, 1),分别表⽰全局因⼦,趋势因⼦,周期性因⼦中最近时间点数据对预测数据的影响程度。y 为经验数据,L为周期。
表⽰使⽤t时间点的估计值预测t+m时间点的值。
注:预测公式中I(t – L + m)应该为I(t – L + 1 +(m – 1) mod L)
计算步骤
alpha,beta,gamma,y,L,m已知。
(1)初始化S0
S0 = y0
(2)初始化b0
维持生计(3)初始化I1, I2, …, IL
(3)计算所有S,b,I
(4)根据公式预测未来值。其中,t取经验数据最后⼀个时间点,t+m为预测时间点。
累加性Holt-Winters公式
Holt-Winters理解
指数平滑法与Holt-Winters不是建⽴在理论基础上的,⽽是⼀种经验法则。⽂章开发我们讨论了时间序列的分解,Holt-Winters公式正是把时间序列分解为趋势项和周期项。其中趋势项为线性函数s + mb,周期项为c。这⾥⾯趋势项与周期项考虑了指数平滑,即给不同时间点的趋势或者周期性赋予了不同的权重。不过,这⾥的趋势仅仅是线性趋势,在带有季节性的⾮线性趋势预测中,效果可能不那么好。
Holt-Winters的Java实现
下⾯的代码实在google上搜索的,预测公式逻辑有问题,没有对季节项进⾏mod运算,会导致数组越界,有空再修改代码。
cuties
奎宁水packagecoshaho.learn;public classHoltWinters
{public static double[] forecast(int[] y, double alpha, doublebeta,double gamma, int period, int m, booleandebug) {if (y == null) {return null;
}int asons = y.length /period;double a0 =calculateInitialLevel(y, period);double b0 =calculateInitialTrend(y, period);double[] initialSeasonalIndices =calculateSeasonalIndices(y, period, asons);if(debug) {
System.out.println(String.format("Total obrvations: %d, Seasons %d, Periods %d", y.length,
asons, period));
System.out.println("Initial level value a0: " +a0);
System.out.println("Initial trend value b0: " +b0);
printArray("Seasonal Indices: ", initialSeasonalIndices);
}double[] forecast =calculateHoltWinters(y, a0, b0, alpha, beta, gamma,
initialSeasonalIndices, period, m, debug);if(debug) {
printArray("Forecast", forecast);
元宵节 英文}returnforecast;
}private static double[] calculateHoltWinters(int[] y, double a0, double b0, doublealpha,double beta, double gamma, double[] initialSeasonalIndices, int period, int m, booleandebug) {double[] St = new double[y.length];double[] Bt = new
double[y.length];double[] It = new double[y.length];double[] Ft = new double[y.length +m];//Initialize ba values
翻译 英语St[1] =a0;
Bt[1] =b0;for (int i = 0; i < period; i++) {
It[i]=initialSeasonalIndices[i];
}
Ft[m]= (St[0] + (m * Bt[0])) * It[0];//This is actually 0 since Bt[0] = 0
Ft[m + 1] = (St[1] + (m * Bt[1])) * It[1];//Forecast starts from period + 2//Start calculations
for (int i = 2; i < y.length; i++) {//Calculate overall smoothing
if((i - period) >= 0) {
St[i]= alpha * y[i] / It[i - period] + (1.0 - alpha) * (St[i - 1] + Bt[i - 1]);
}el{
St[i]= alpha * y[i] + (1.0 - alpha) * (St[i - 1] + Bt[i - 1]);
}//Calculate trend smoothing
Bt[i] = gamma * (St[i] - St[i - 1]) + (1 - gamma) * Bt[i - 1];//Calculate asonal smoothing
if((i - period) >= 0) {
It[i]= beta * y[i] / St[i] + (1.0 - beta) * It[i -period];
}//Calculate forecast
if( ((i + m) >=period) ){
Ft[i+ m] = (St[i] + (m * Bt[i])) * It[i - period +m];
}if(debug){
System.out.println(String.format("i = %d, y = %d, S = %f, Bt = %f, It = %f, F = %f", i,
y[i], St[i], Bt[i], It[i], Ft[i]));
}
}returnFt;
*
*@return- Initial Level St[1]*/
private static double calculateInitialLevel(int[] y, intperiod) {/**double sum = 0;
for (int i = 0; i < period; i++) {
sum += y[i];
}
igadgetreturn sum / period;
**/
return y[0];
*@return- Initial trend - Bt[1]*/
private static double calculateInitialTrend(int[] y, intperiod){double sum = 0;for (int i = 0; i < period; i++) {
sum+= (y[period + i] -y[i]);
}return sum / (period *period);
*@return- Seasonal Indices.*/
跑业务的技巧
private static double[] calculateSeasonalIndices(int[] y, int period, intasons){double[] asonalAverage = newracket
double[asons];double[] asonalIndices = new double[period];double[] averagedObrvations = new double[y.length];for (int i = 0; i < asons; i++) {for (int j = 0; j < period; j++) {
asonalAverage[i]+= y[(i * period) +j];
}
asonalAverage[i]/=period;
}for (int i = 0; i < asons; i++) {for (int j = 0; j < period; j++) {
averagedObrvations[(i* period) + j] = y[(i * period) + j] /asonalAverage[i];
}
}for (int i = 0; i < period; i++) {for (int j = 0; j < asons; j++) {
asonalIndices[i]+= averagedObrvations[(j * period) +i];
fridge是什么意思
}
asonalIndices[i]/=asons;
}returnasonalIndices;
}private static void printArray(String description, double[] data){
System.out.println(String.format("******************* %s *********************", description));for (int i = 0; i < data.length; i++) {
System.out.println(data[i]);
}
System.out.println(String.format("*****************************************************************", description));
}
}