如何执行最近n次观察的计算

时间:2014-09-04 06:45:48

标签: sas

如何对数据集中的最后n个观察值进行计算 例如,如果我有10个观察,我想创建一个变量,它将另一个变量的最后5个值相加。请不要建议我滞后5次或使用模块( N )。我需要一个更优雅的解决方案。

使用下面的代码alpha是我拥有的数据集,而bravo是我需要的数据集。

data alpha; 
    input lima @@ ;
    cards ;
3 1 4 21 3 3 2 4 2 5
; 
run ;

data bravo;
input lima juliet;
cards;
3 .
1 .
4 .
21 .
3 32
3 32
2 33
4 33
2 14
5 16
;
run;

提前谢谢你!

3 个答案:

答案 0 :(得分:0)

我可以提供相当难看的解决方案:

  1. 运行数据步骤并将增加的数字添加到每个
  2. 运行sql步骤并添加 max(group)
  3. 运行另一个数据步骤并检查(2) - (1)中的值是否小于5.如果是,请指定 _num_to_sum _ 变量(例如)要求和的值,否则留空或指定0。
  4. 并且最后使用 sum(_num_to_sum _)执行sql步骤,并通过将变量从(1)分组来对结果进行分组。
  5. 编辑:我已经以更加紧凑的方式添加了这个概念的实例。

    input var1 $ var2;
    cards;
    aaa 3
    aaa 5
    aaa 7
    aaa 1
    aaa 11
    aaa 8
    aaa 6
    bbb 3
    bbb 2
    bbb 4
    bbb 6
    ;
    run;
    
    data step1;
        set sourcetable;
        by var1;
        retain obs 0;
        if first.var1 then obs = 0;
        else obs = obs+1;
        if obs >=5 then to_sum = var2;
    run;
    
    proc sql;
        create table rezults as
            select distinct var1, sum(to_sum) as needed_summs
            from step1
            group by var1;
    quit;
    

答案 1 :(得分:0)

您可以在数据步骤中执行此操作,也可以使用SAS / ETS中的PROC EXPAND(如果可用)。

对于数据步骤,我们的想法是您从累积总和(summ)开始,但要跟踪到目前为止添加的值的数量(ninsum)。一旦达到5,就开始将累积和输出到目标变量(juliet),然后从下一步开始减去滞后-5值,只存储最后五个值的总和。

data beta;
    set alpha;
    retain summ ninsum 0;

    summ + lima;
    ninsum + 1;
    l5 = lag5(lima);

    if ninsum = 6 then do;
        summ = summ - l5;
        ninsum = ninsum - 1;
    end;

    if ninsum = 5 then do;
        juliet = summ;
    end;

run;

proc print data=beta;
run;

然而,有一个程序可以执行所有类型的累积,移动窗口等计算:PROC EXPAND,其中这实际上只是一行。我们只是告诉它在宽度为5的窗口中计算向后移动的总和,并将前4个观察值设置为缺失(默认情况下,它会将你的序列扩展为左边的0')

proc expand data=alpha out=gamma;
       convert lima = juliet   / transformout=(movsum 5 trimleft 4);
 run;

proc print data=gamma;
run;

修改

如果要进行更复杂的计算,则需要在保留变量中携带先前的值。我以为你想避免这种情况,但现在是:

data epsilon;
    set alpha;
    array lags {5};
    retain lags1 - lags5;

    /* do whatever calculation is needed */
    juliet = 0;
    do i=1 to 5;
        juliet = juliet + lags{i};
    end;

    output;

    /* shift over lagged values, and add self at the beginning */
    do i=5 to 2 by -1;
        lags{i} = lags{i-1};
    end;
    lags{1} = lima;

    drop i;
run;

proc print data=epsilon;
run;

答案 2 :(得分:0)

万一有人读这个:) 我解决了它需要它解决的方式。虽然现在我更好奇两者中的哪一个(保留和我的解决方案)在计算/处理时间方面更优。

这是我的解决方案:

data bravo(keep = var1 summ);
    set alpha;
    do i=_n_ to _n_-4 by -1;
        set alpha(rename=var1=var2) point=i;
        summ=sum(summ,var2);        
    end;
run;