SAS中的分区运行总计

时间:2015-09-21 15:36:43

标签: sql sum sas running-total

如何为现有数据集创建一个新列,该数据集是现有列的运行总计 - 由某个标识符分区?

ID |  Value |     New Value
---|--------|--------------------
1  |   10   |     10
1  |   5    |     15  = 10 + 5
1  |   3    |     18  = 10 + 5 + 3
2  |   45   |     45
2  |   15   |     60  = 45 + 15

我习惯使用简单的SUM()OVER()语句在SQL(Oracle)中完成此操作,但PROC SQL中显然不支持该语法。

如果可能的话,我想在PROC SQL中实现这一点(我对SQL比SAS编码更有经验。)

谢谢!

麦克

4 个答案:

答案 0 :(得分:4)

在数据步骤中,这是通过sum statement完成的。

data want;
  set have;
  by id;
  if first.id then running_total=0;
  running_Total + value;
run;

在PROC SQL中,除非你有一个排序变量(你可以做这样的事情),否则这是不可能的:

proc sql;
  create table want as
   select id, value,
     (select sum(value) from have V
     where V.id=H.id and V.ordervar le H.ordervar
     ) as running_total
   from have H
 ;
quit;

但SAS没有partition by概念 - SAS数据步骤远比那更强大。

答案 1 :(得分:2)

我通常使用data步而非proc sql在SAS中运行总计。理论上你可以用proc sql和交叉连接来做到这一点,但这在现实世界中并不是很实用。

第1步:按ID值对数据进行排序

proc sort data=have;
     by ID;
run;

第2步:使用和语句计算运行总计

data want;
    set have;
    by ID;

    New_Value+Value;

    output;

    if(last.ID) then New_Value = 0;
 run;

<强>解释

分组处理是SAS最强大的工具之一。当您按ID值排序并在数据步骤中对其使用by-statement时,您将解锁两个新的特殊布尔变量:first.<by-group variable>last.<by-group variable>. SAS确切知道何时启动一组ID变量,当你进行分组处理时停止(你实际上可以使用一个名为notsorted的特殊选项来逃避而不对ID值进行排序,但这是一个高级概念)。在你的情况下,让我们来看看它是如何工作的:

ID Value first.ID last.ID
1  10    1        0
1  5     0        0
1  3     0        1
2  45    1        0 
2  15    0        1

如果ID组中只有一个观察值,first.IDlast.ID都会为1。

SAS中有一个特殊的声明,称为sum语句,它既可以保留变量,也可以对变量求和。 SAS本质上是一种循环语言;每当它通过data步骤时,它只查看一条记录和一条记录。当它到达data步骤的底部并返回到顶部时,开始读取表中的下一条记录,并假设所有变量现在再次丢失,直到它读取或计算变量的值。你输出的东西是程序数据向量的内容。在后台,这就是你在操纵的东西。

默认情况下,只有在达到run边界后才会输出到数据集。如果您明确告诉SAS输出,它只会在您告诉它时输出。为了累积一个变量,我们想告诉SAS四件事:

  1. 保留变量的先前值(在读取新记录时不要将其重置为缺少)
  2. 将变量添加到自身
  3. 将值添加到自身后的输出
  4. 输出后,它是一组ID变量中的最后一个观察值,将我的累积变量重置为0
  5. 实现步骤1&amp; 2,你可以做两个选择:

     data want;
          set have;
          retain New_Value;
    
          New_Value = sum(New_Value, Value);
    

    OR

     data want;
           set have;
           New_Value+Value;
    

    请注意,第二个选项与第一个选项完全相同,但工作量较少。把它想象成一条捷径。这称为Sum语句。看起来它在语法上是错误的,但它是一个特殊的,非常有用的案例。

    要实现第3步,我们只是告诉SAS默认输出,而不是默认情况下在数据步骤结束时输出:

    data want;
        set have;
    
        New_Value+Value;
    
        output;
    

    如果按原样运行上面的代码,New_Value将无限期地加起来,直到它到达文件的最后。我们希望在到达新ID组后重置此值。我们使用by-group处理解锁这两个布尔变量,在输出后在指定条件下将New_Value重置为0:

    data want;
        set have;
        by ID;
    
        New_Value+Value;
    
        output;
    
        if(last.ID) then New_Value = 0;
    run;
    

    New_Value将不会重置为0,除非我们处于指定ID组的最后一次观察中。请注意,我们将条件if语句放在输出语句下面。如果超过此值,您会看到以下现象:

    ID Value New_Value first.ID last.ID
    1  10    10         1        0
    1  5     15         0        0
    1  3      0         0        1
    2  45    45         1        0 
    2  15     0         0        1
    

    我们希望在 New_Value重置为0之前输出累积和

    您可以使用其他一些SAS程序来执行类似的操作,但它们是针对特定情况设计的。在这种情况下,您可以重新调整它们以执行您想要的操作,但最好在跳转到程序重新调整之前学习data步骤处理。

答案 2 :(得分:0)

这是另一种选择:

data want;
do until (last.id);
    set have;
    by id;
    new_value + value;
    output;
end;
new_value = 0;
run;

答案 3 :(得分:-1)

乔 - 你的回答无论出于什么原因都没有用,但让我走上了正确的轨道去弄明白。谢谢!

data want;
    set have;
    by id;
    if first.id then running_total = 0;
    if first.id then retained_total = 0;
    running_total = retained_total + value;
    retained_total = running_total;
    retain retained_total;
run;