Proc expand for irregular time series
Proc expand for irregular time series
如何使用 PROC EXPAND 计算具有中断的时间序列的移动平均值?我正在寻找一种更有效的方法来进行此计算,因为由于服务器限制,大型数据集上的 DATA 步和 JOINS 需要很长时间才能执行。
数据:
data have(drop=i);
call streaminit(1);
do i = 1 to 20;
period = i;
if i > 10 then period = i + 5;
if i >17 then period = i + 6;
x = round(rand('uniform')*10,1.);
output;
end;
run;
│ period │ x │
├────────┼────┤
│ 1 │ 9 │
│ 2 │ 10 │
│ 3 │ 5 │
│ 4 │ 9 │
│ 5 │ 7 │
│ 11 │ 9 │
│ 12 │ 9 │
│ 13 │ 5 │
│ 15 │ 8 │
│ 16 │ 9 │
注意period变量中有两个断点:5-11和13-15。
这是预期结果(3 个月移动平均线):
Proc sql;
create table want as
select a.period, a.x
,mean(b.x) as x_avg format=10.2
from have as a
left join have as b
on a.period -3 < b.period <= a.period
group by 1,2;
Quit;
│ period │ x │ x_avg │
├────────┼────┼───────┤
│ 1 │ 9 │ 9.00 │
│ 2 │ 10 │ 9.50 │
│ 3 │ 5 │ 8.00 │
│ 4 │ 9 │ 8.00 │
│ 5 │ 7 │ 7.00 │
│ 11 │ 9 │ 9.00 │
│ 12 │ 9 │ 9.00 │
│ 13 │ 5 │ 7.67 │
│ 15 │ 8 │ 6.50 │
│ 16 │ 9 │ 8.50 │
您可以通过一点修改使 SQL 更快。
proc sql noprint;
create table want2 as
select a.period, a.x ,mean(b1.x,b2.x,a.x) as x_avg format=10.2
from have as a
left join have as b1 on a.period -2 = b1.period
left join have as b2 on a.period -1 = b2.period
order by a.period;
quit;
数据步长更快。
data want3;
set have;
period_l2 = lag2(period);
period_l1 = lag(period);
x_l2 = ifn(period_l2=period-2,lag2(x),ifn(period_l1=period-2,lag(x),.));
x_l1 = ifn(period_l1=period-1,lag(x),.);
x_avg = mean(x_l2,x_l1,x);
run;
如果系列的长度不再是3,使用数组和mean(of _array_[*])
来帮助自己。
使用 proc timeseries
添加每个间隙之间的缺失值,然后 运行 通过 proc expand
和 method=none
。我们将每天考虑间隔,因为它一次增加一个值。过滤掉您的最终数据集,使 x
.
没有缺失值
proc timeseries data = have
out = have_ts;
id period interval=day setmissing=missing;
var x;
run;
proc expand data = have_ts
out = want(where=(NOT missing(x)) );
id period;
convert x = x_avg / method=none transform=(moveave 3);
run;
您需要使用 proc datasets
将 period
重新格式化为 8.
,因为 proc timeseries
需要将其视为日期。
proc datasets lib=work nolist;
modify want;
format x 8.;
quit;
如何使用 PROC EXPAND 计算具有中断的时间序列的移动平均值?我正在寻找一种更有效的方法来进行此计算,因为由于服务器限制,大型数据集上的 DATA 步和 JOINS 需要很长时间才能执行。
数据:
data have(drop=i);
call streaminit(1);
do i = 1 to 20;
period = i;
if i > 10 then period = i + 5;
if i >17 then period = i + 6;
x = round(rand('uniform')*10,1.);
output;
end;
run;
│ period │ x │
├────────┼────┤
│ 1 │ 9 │
│ 2 │ 10 │
│ 3 │ 5 │
│ 4 │ 9 │
│ 5 │ 7 │
│ 11 │ 9 │
│ 12 │ 9 │
│ 13 │ 5 │
│ 15 │ 8 │
│ 16 │ 9 │
注意period变量中有两个断点:5-11和13-15。
这是预期结果(3 个月移动平均线):
Proc sql;
create table want as
select a.period, a.x
,mean(b.x) as x_avg format=10.2
from have as a
left join have as b
on a.period -3 < b.period <= a.period
group by 1,2;
Quit;
│ period │ x │ x_avg │
├────────┼────┼───────┤
│ 1 │ 9 │ 9.00 │
│ 2 │ 10 │ 9.50 │
│ 3 │ 5 │ 8.00 │
│ 4 │ 9 │ 8.00 │
│ 5 │ 7 │ 7.00 │
│ 11 │ 9 │ 9.00 │
│ 12 │ 9 │ 9.00 │
│ 13 │ 5 │ 7.67 │
│ 15 │ 8 │ 6.50 │
│ 16 │ 9 │ 8.50 │
您可以通过一点修改使 SQL 更快。
proc sql noprint;
create table want2 as
select a.period, a.x ,mean(b1.x,b2.x,a.x) as x_avg format=10.2
from have as a
left join have as b1 on a.period -2 = b1.period
left join have as b2 on a.period -1 = b2.period
order by a.period;
quit;
数据步长更快。
data want3;
set have;
period_l2 = lag2(period);
period_l1 = lag(period);
x_l2 = ifn(period_l2=period-2,lag2(x),ifn(period_l1=period-2,lag(x),.));
x_l1 = ifn(period_l1=period-1,lag(x),.);
x_avg = mean(x_l2,x_l1,x);
run;
如果系列的长度不再是3,使用数组和mean(of _array_[*])
来帮助自己。
使用 proc timeseries
添加每个间隙之间的缺失值,然后 运行 通过 proc expand
和 method=none
。我们将每天考虑间隔,因为它一次增加一个值。过滤掉您的最终数据集,使 x
.
proc timeseries data = have
out = have_ts;
id period interval=day setmissing=missing;
var x;
run;
proc expand data = have_ts
out = want(where=(NOT missing(x)) );
id period;
convert x = x_avg / method=none transform=(moveave 3);
run;
您需要使用 proc datasets
将 period
重新格式化为 8.
,因为 proc timeseries
需要将其视为日期。
proc datasets lib=work nolist;
modify want;
format x 8.;
quit;