背景
在时间序列数据处理中,原始时间序列采样间隔非常密集,有的为分钟级,有的甚至是秒级,在分析时,依据分析目的不同,需要进行不同尺度的转化,若要查看其日变化情况或季节变化,直接使用海量的秒级原始数据,其整体变化特征通常会被大量的细节数据所掩盖。所以求取日平均、月平均等是常见的操作。
这里利用matlab数据内置的find、mean等函数,可以方便的求得。算法不一定是最优的,但是,可以实现目的,记录于此,便于日后查找,也为不想自己编写的朋友提供参考。
问题描述
以某地温度时间序列为例,该数据的时间分辨率为秒级,数据量非常大,第一列为时间数据,第二列为温度数据。
数据截图
如何求取时平均呢?
解决思路
首先,将第一列化为日期向量的形式。
mydata=datevec(dd(:,1)); %将日期字符串化为日期向量
然后通过循环,求取统一比较时间级别的量,这里核心用find函数,具体代码如下
temp=data(:,1:n);
temp=temp-dd;
temp=abs(temp);%必须加绝对值,防止正负抵消的情况,浑水摸鱼
s0=sum(temp,2);
bz1=find(s0==0);
然后,将在范围之内的数据进行平均,得到该时间级别上的平均值,将剩余的数据赋值给原始数据,继续进入下一轮的循环
最后,当剩余矩阵为空时,则循环结束。
需要注意的两个地方:
(1)判断时间级别相同,采用了向量减法,然后对结果进行求和,可能会出现正负抵消的情况,此时,从结果上看,也是为0,而这和要比较的时间级别是不同的,序号对差求取绝对值,以剔除这种情况。
(2)求和函数,要区分是列方向求和还是行方向求和,这个细节可以参阅matlab帮助,实在不行,用一个简答的小矩阵进行试验,当结果正确的时候,则证明算法是正确的。
完整的代码如下:
mydata=datevec(dd(:,1)); %将日期字符串化为日期向量
t=dd(:,2); %提取温度数据
t=cell2mat(t); %将细胞数据转化为矩阵
mydata=[mydata t]; %合并数据
tempdata=mydata; %暂存原始数据,防止出错,原数据被污染。
rsltData=[];
idx=1;
numD=2;%需要平均的维数,1-年 2-月 3-日 4-时 5-分 6-秒
while 1
[bz1,bz2]=findsamehour(tempdata,tempdata(1,1:numD));
rsltData(idx,1:numD)=tempdata(1,1:numD);
rsltData(idx,numD+1:6)=0; %为了严谨,平均时间尺度以下的值赋为0,避免具体时间造成误导
dataInRegion=tempdata(bz1,:); %需要平均的数据,7仅是本数据的特列,具体数据所在列数以具体情况而定
dataOutRegion=tempdata(bz2,:);
rsltData(idx,7)=mean(dataInRegion(:,7));
if(length(bz2)<=0)
break;
end
idx=idx+1;%序号递增,进入下一轮循环
tempdata=dataOutRegion;% 更新mydata的值
idx
end
搜索统一时间段的函数
`
function [bz1,bz2]=findsamehour(data,dd)
% y=2018;
% m=1;
% d=1;
% h=0;
[m,n]=size(data);
if(n<6)
error('输入的数据列小于6')
return;
end
[m,n]=size(dd);
if(n>6)
error('输入的时间向量列维数大于6')
return;
end
temp=data(:,1:n);
temp=temp-dd;
temp=abs(temp);%必须加绝对值,防止正负抵消的情况,浑水摸鱼
s0=sum(temp,2);
bz1=find(s0==0);
bz2=find(s0~=0);
end
绘图函数
%% 绘图
afigure;
aplot(dt,mydata(:,7),'.g');
xlabel('time');
ylabel('temperature(℃)');
hold on
aplot(datetime(rsltData(:,1:6)),rsltData(:,7),'-r');
xtickformat('MM-dd')
aplot(datetime(rsltData2(:,1:6)),rsltData2(:,7),'o:b');
legend({'raw data','hour mean data','month mean data'})
axis tight
结果
最终结果可以用图直观表示