指数平滑法

摘要:
指数平滑法认为,经验数据越老,对趋势的影响越小。三次指数平滑二次指数模型是线性的。对于非线性趋势预测,我们可以使用三次指数平滑方法。累积霍尔特温特斯公式霍尔特温特斯明白指数平滑法和霍尔特温特s不是基于理论,而是经验法则。在这种情况下,对趋势项和周期项考虑指数平滑,即在不同的时间点对趋势或周期赋予不同的权重。
时间序列分解

大量时间序列的观测样本表现出趋势性、季节性和随机性,或者三者中的其一或其二。于是,我们认为每个时间序列,都可以分为三个部分的叠加

指数平滑法第1张

其中,T是趋势项,S是季节项,R是随机项。

上述公式表现了趋势项和季节项是累加的,实际应用场景中,趋势项和季节项可能是累乘的,时间序列可以分解为如下公式

指数平滑法第2张

实际应用中,随机项R的期望为0,没有规律,并且绝对值不大。所以在应用场景中我们往往省略掉R,R称作噪声。预测公式如下

指数平滑法第3张

指数平滑法第4张

一次指数平滑法

线性回归算法中,每个经验点的权重是一致的,即很早以前的经验数据也可能对预测数据有较大的影响。很多实际场景中,未来一段时间的趋势可能和在最近一段时间的趋势关系更加紧密。比如小明去年数学考试成绩一直不及格,今年连续多次考试90多分,预测小明下一次数学考试的成绩,情理上90多分的可能性更高。采用传统的线性回归算法,预测结果可能是70多分。

指数平滑法认为越老的经验数据对趋势的影响越小。我们假定时间t的观测值为y(t),时间t的预测值为S(t),则时间t+1的预测值S(t+1)为

指数平滑法第5张

a的取值范围(0, 1),a越大,最近时间点的观测值对预测值的影响越大。

假设我们有t个经验数据,根据上述一次指数平滑公式,预测值S(t + n) = S(t + 1),预测值不具备趋势。

二次指数平滑

我们对一次指数平滑值再进行指数平滑,可以获得趋势。二次指数平滑法的预测模型为:

指数平滑法第6张

指数平滑法第7张

指数平滑法第8张

式中:指数平滑法第9张分别为时间t和时间t - 1的二次指数平滑值。

三次指数平滑

二次指数模型是线性的,对于非线性趋势预测我们可以使用三次指数平滑法。公式如下

指数平滑法第10张

指数平滑法第11张

指数平滑法第12张

指数平滑法第13张

指数平滑法第14张

Holt-Winters算法

对于具有周期性的趋势预测,我们可以使用Holt-Winters算法。累乘性Holt-Winters公式如下

指数平滑法第15张  

其中,alpha,beta,gamma取值范围为(0, 1),分别表示全局因子,趋势因子,周期性因子中最近时间点数据对预测数据的影响程度。y为经验数据,L为周期。

指数平滑法第16张表示使用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

指数平滑法第17张 

(3)初始化I1, I2, …, IL

指数平滑法第18张

(3)计算所有S,b,I

(4)根据公式预测未来值。其中,t取经验数据最后一个时间点,t+m为预测时间点。

指数平滑法第16张

累加性Holt-Winters公式

 指数平滑法第20张

指数平滑法第21张

Holt-Winters理解

指数平滑法与Holt-Winters不是建立在理论基础上的,而是一种经验法则。文章开发我们讨论了时间序列的分解,Holt-Winters公式正是把时间序列分解为趋势项和周期项。其中趋势项为线性函数s + mb,周期项为c。这里面趋势项与周期项考虑了指数平滑,即给不同时间点的趋势或者周期性赋予了不同的权重。不过,这里的趋势仅仅是线性趋势,在带有季节性的非线性趋势预测中,效果可能不那么好。

Holt-Winters的Java实现

下面的代码实在google上搜索的,预测公式逻辑有问题,没有对季节项进行mod运算,会导致数组越界,有空再修改代码。

package coshaho.learn;

public class HoltWinters 
{
    public static double[] forecast(int[] y, double alpha, double beta,
            double gamma, int period, int m, boolean debug) {

        if (y == null) {
            return null;
        }

        int seasons = y.length / period;
        double a0 = calculateInitialLevel(y, period);
        double b0 = calculateInitialTrend(y, period);
        double[] initialSeasonalIndices = calculateSeasonalIndices(y, period, seasons);

        if (debug) {
            System.out.println(String.format(
                    "Total observations: %d, Seasons %d, Periods %d", y.length,
                    seasons, 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);
        }

        return forecast;
    }
    
    private static double[] calculateHoltWinters(int[] y, double a0, double b0, double alpha,
            double beta, double gamma, double[] initialSeasonalIndices, int period, int m, boolean debug) {
        
        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 base 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]);
            } else {
                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 seasonal 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]));
            }
        }
        
        return Ft;
    }

    /**
     * See: http://robjhyndman.com/researchtips/hw-initialization/
     * 1st period's average can be taken. But y[0] works better.
     * 
     * @return - Initial Level value i.e. St[1]
     */
    private static double calculateInitialLevel(int[] y, int period) {

        /**        
         double sum = 0;
        for (int i = 0; i < period; i++) {
            sum += y[i];
        }
        
        return sum / period;
         **/
        return y[0];
    }
    
    /**
     * See: http://www.itl.nist.gov/div898/handbook/pmc/section4/pmc435.htm
     * 
     * @return - Initial trend - Bt[1]
     */
    private static double calculateInitialTrend(int[] y, int period){
        
        double sum = 0;
        
        for (int i = 0; i < period; i++) {            
            sum += (y[period + i] - y[i]);
        }
        
        return sum / (period * period);
    }
    
    /**
     * See: http://www.itl.nist.gov/div898/handbook/pmc/section4/pmc435.htm
     * 
     * @return - Seasonal Indices.
     */
    private static double[] calculateSeasonalIndices(int[] y, int period, int seasons){
                        
        double[] seasonalAverage = new double[seasons];
        double[] seasonalIndices = new double[period];
        
        double[] averagedObservations = new double[y.length];
        
        for (int i = 0; i < seasons; i++) {
            for (int j = 0; j < period; j++) {
                seasonalAverage[i] += y[(i * period) + j];
            }
            seasonalAverage[i] /= period;
        }
        
        for (int i = 0; i < seasons; i++) {
            for (int j = 0; j < period; j++) {
                averagedObservations[(i * period) + j] = y[(i * period) + j] / seasonalAverage[i];                
            }            
        }
        
        for (int i = 0; i < period; i++) {
            for (int j = 0; j < seasons; j++) {
                seasonalIndices[i] += averagedObservations[(j * period) + i];
            }            
            seasonalIndices[i] /= seasons;
        }
        
        return seasonalIndices;
    }
    
    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));
    }
}

免责声明:文章转载自《指数平滑法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇submit text3的激活与使用canvas (画布)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

微信支付服务商模式支付与普通微信支付的配置区别

chapter=7_7&index=5注:与普通微信支付相比,源代码是上述7/8之间的区别,其他可以看作是服务提供商自己的微信支付配置;...

Windows 远程桌面连接ubuntu及xrdp的一些小问题(远程桌面闪退、连接失败、tab补全功能,无菜单栏,error

想要修改,在windowsmanager中,keyboard里将用到Super+Tab的快捷键clear掉即可。解决:通过设置sesman.in文件内的参数解决:cat/etc/xrdp/sesman.inivi/etc/xrdp/sesman.ini可以修改会话设置:将最大会话限制该大MaxSessions=50;将KillDisconnected=1;则...

Linux中使用gdb dump内存

在应急响应中,我们经常需要转储某个内存块以进行分析。今天我们将讨论使用gdb命令转储sshd进程的内存。根据Linux系统的设计理念,内核只提供转储内存的机制。用户要转储什么样的内存以及要转储多少内存是策略问题,由用户决定。之后,转到/tmp目录,可以从dump中看到sshd.dmp内存字符串-10sshd.dump#,以查看sshd.ddump内存中至少超...

将HTML文件转换为MD文件

html格式转md格式#模块html2textpipinstallhtml2text/pip3installhtml2text测试:importhtml2textashttext_maker=ht.HTML2Text()#读取html格式文件withopen('./*.html','r',encoding='UTF-8')asf:htmlpage=f.rea...

删除隐藏网卡(本机IP地址被占用)4个方法

关闭注册表,重新启动windowsxp或重新登录,在设备管理器中单击查看->显示隐藏设备,展开“网络适配器”卸载原来的老网卡,在重设IP就不会显示IP地址被占用了。方法2:要删除系统中隐藏的网卡,我们必须运行regedit打开注册表编辑器,找到HKEY_LOCAL_MCHINE\SYSTEM\CurrentControlSetControl\Network\...

windows系统磁盘IO性能测试(CrystalDiskMark硬盘检测工具)

CrystalDiskMark的具体使用方法如下:Seq:连续读写硬盘检测512K:随机读写硬盘探测4KQD32:随机读和写硬盘探测4KQD32:NCQ和AHCI模式2的随机读写探测。单击“全部”以检测所有项目。CrystalDiskMark硬盘检测工具中文版下载3。正在测试硬盘读写速度。CrystalDiskMark的常见问题1。测试硬盘时,Crystal...