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 expandmethod=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 datasetsperiod 重新格式化为 8.,因为 proc timeseries 需要将其视为日期。

proc datasets lib=work nolist;
    modify want;
        format x 8.;
quit;