在引入时间序列前,先介绍几个matlab函数
matlab中的gallery函数简析
Matlab 中的 gallery 函数是一个测试矩阵生成函数。当我们需要对某些算法进行测试的时候,可以利用gallery函数来生成各种性质的测试矩阵。其用法如下:
[A,B,C,…] =gallery(matname,P1,P2,…,classname)
其中matname表示矩阵性质,classname表示矩阵元素是single还是double
例如:
x=gallery('uniformdata',[1 10],0)
>>x =
1 至 7 列
0.9501 0.2311 0.6068 0.4860 0.8913 0.7621 0.4565
8 至 10 列
0.0185 0.8214 0.4447
y = gallery('uniformdata',[1 10],1)
>>y =
1 至 7 列
0.9528 0.7041 0.9539 0.5982 0.8407 0.4428 0.8368
8 至 10 列
0.5187 0.0222 0.3759
其中 uniformdata 表示均匀分布,[1 10] 表示x是一个长度为10的数组,最后一个参数 0和1表示不同的矩阵,如果反复引用x=gallery(‘uniformdata’,[1 10],0),那么得到的数组总是相同的。
下面我们按照测试矩阵生成的点画出来
x=gallery('uniformdata',[1 10],0);
y = gallery('uniformdata',[1 10],1);
plot(x,y,'o')
hold on
voronoi(x,y)
如下图所示:
其中,中心点为按照某种模式生成的点。边框为voronoi diagram
模拟时间序列分析
介绍了刚才的gallery函数,下面基于其模拟的时间序列数值进行相关操作。
模拟
创建一个模拟数据集并计算其平均值。假设 sdata表示股票的每日价格变化。
t = 0:200;
dailyFluct = gallery('normaldata',size(t),2);
sdata = cumsum(dailyFluct) + 20 + t/100;
%计算均值
mean_data = mean(sdata)
画出来生成的模拟数据大概长成这样,我们假设横坐标为时间,纵坐标为股票价格。从模拟函数sdata = cumsum(dailyFluct) + 20 + t/100和图看来数据是具有趋势性的。
去趋势
目的:去趋势(detrend)处理可以消除传感器在获取数据时产生的偏移对后期计算产生的影响。从数据中删除趋势可以将分析集中在数据趋势本身的波动上。但是,去趋势的意义取决于自己的研究的目的。
方法:数据去趋势,就是对数据减去一条最优(最小二乘)的拟合直线、平面或曲面,使去趋势后的数据均值为零。
在matlab中,可以使用detrend函数去除时间序列x中的均值或线性趋势,这在FFT处理中尤其常用。
格式参数如下:
y = detrend(x) % 消除时间序列中的线性趋势项
y = detrend(x,'constant') % 消除时间序列中的均值
y = detrend(x,'linear',bp) % 分段消除时间序列中的线性趋势项,bp为分段点向量
例如如:
sig = [0 1 -2 1 0 1 -2 1 0]; % 无线性趋势的信号
trend = [0 1 2 3 4 3 2 1 0]; % 有两段线性的趋势
x = sig+trend; % 将上面趋势叠加到信号上
y = detrend(x,'linear',5) % 根据指定的分段点去除两段线性趋势
我们对上述数据进行去趋势处理如下:
%计算去趋势数据,并且从原始数据中移除
detrend_sdata = detrend(sdata);
trend = sdata - detrend_sdata;
mean(detrend_sdata)
最后,我们绘图如下:
完整代码:
t = 0:200;
dailyFluct = gallery('normaldata',size(t),2);
sdata = cumsum(dailyFluct) + 20 + t/100;
%计算均值
mean_data = mean(sdata);
figure(1)
plot(t,sdata,'r')
legend('Original Data','Location','northwest');
xlabel('Time (days)');
ylabel('Stock Price (dollars)');
%计算去趋势数据,并且从原始数据中移除
detrend_sdata = detrend(sdata);
%原数据减去去趋势后的数据就是趋势项了
trend = sdata - detrend_sdata;
%计算去趋势后的均值,发现极小接近于0
mean(detrend_sdata)
hold on
plot(t,trend,':r')
plot(t,detrend_sdata,'m')
plot(t,zeros(size(t)),':k')
legend('原始数据','趋势','去趋势后数据',...
'去趋势后均值','Location','northwest')
xlabel('时间 (天)');
一个具体的案例 --移动开户数分析
我们有一份移动公司两年间共计700余天的每日开户树,我们想探寻其中的随机因素。
去趋势项和去季节项
绘制原开户数据的变化趋势如下:
图一.原开户数据趋势变化的观察
可以发现,开户数在局部区间的极值变化具有一定的周期性。但是数据太多且有点杂乱。
为了更好的观察数据的规律,拟将数据进行滑动平均处理,在一定程度上更能看出规律性。并且,依据两年的月数天数变化,设置标记每月天数变化的向量,计算每月,每个季度,每年的平均开户数进行观察。计算并绘制得到下图:
图二.开户数据趋势变化周期的观察
上图红色标记为2012年,蓝色标记为2013年。总的看来均有上升的趋势。图二左上角绘制的是2012和2013的开户数滑动平均观察(使用matlab smooth函数,滑动窗口设置为30),容易发现在年这个层面上趋势具有较大的相关性,一年显然可以是一个大周期的刻画。但是这个周期太大了,如果选取这个周期做去季节性,显然会损失大量数据。因此,我们想找到一个更小的周期来刻画,其实我们还可以发现图一中有明显的小起伏,经验证起伏平均间隔为30即一个月,那么一个月是否为一个周期呢?右上图是按月进行平均的统计值绘制,起伏貌似没有什么规律。但是还是可以作为参考。左下角图绘制的是季度的平均开户数变化,可以发现两个季度为一个周期,因为起伏在两个周期中进行。右下角图绘制的是年平均变化图,如我们所料,随着移动互联网的普及,2013年开户平均数比2012年高。
综上观察,我们可以得出以下结论:
1.一个月应该是一个最小周期,两个季度是一个中周期,一年为一个确定的大周期。
2.开户人数有明显的上升趋势。
3.由观测值我们可以认为存在异常值。
2.数据的预处理
2.1缺失值处理
数据中不存在缺失值
2.2异常值处理
拟采用三倍标准差即拉以达法则筛选异常值,考虑到时间序列的短期影响性,用其周围值平均代替。
3.平稳化–去趋势与去周期
进行了简单的观察和数据预处理后,我们开始正式进行时间序列平稳化的操作。考虑到有两年,我们从单独考虑2012,2013,然后集中考虑2012和2013来进行处理和检验。
3.1去趋势
由于数据变化有一定的集中性,且有滑动平均看来近似可以用一次函数拟合。所以采用一次差分的方法去除数据的趋势项。这里采用diff函数实现一次差分。去趋势后,我们进行了如下的观察:
图三.周期为一个月的检验图
我们发现相邻极值点间的时间差距十分接近于一个月,这让我们欣喜万分。
3.2去周期
由以上的观察数据和去趋势后数据综合考虑,采用一个月作为周期是个不错的选择。这里自定义d步差分函数对去趋势后的数据进行去周期的处理。
经过3.1和3.2,我们得到如下结果:
图四.2012年去趋势和去周期比较图 图五.2013年去趋势和去周期比较图
图六.2012-2013年去趋势和去周期比较图
肉眼看来,效果还算不错,从均值线看来均值均十分接近于0。为了更客观的看待平稳的效果,采用自相关图还进行平稳性的验证。
自相关性平稳性检验结果如下:
图七.自相关图检验平稳性
从自相关图看来,经过去趋势和去周期后的数据的确是平稳的。 经过以上步骤,我们就成功的将非平稳的时间序列转换为了平稳的时间序列,得到了随机误差项的表示。