Sql SAS中的分区运行总计
如何为现有数据集创建一个新列,该数据集是由某个标识符分区的现有列的运行总数Sql SAS中的分区运行总计,sql,sum,sas,cumulative-sum,Sql,Sum,Sas,Cumulative Sum,如何为现有数据集创建一个新列,该数据集是由某个标识符分区的现有列的运行总数 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 我习惯于在SQL(
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
我习惯于在SQL(Oracle)中使用简单的SUM()OVER()语句来实现这一点,但PROC SQL显然不支持这种语法
如果可能的话,我希望在procsql中实现这一点(我对SQL的经验要比SAS编码丰富得多)
谢谢
Mike。在数据步骤中,这是通过
sum语句完成的
data want;
set have;
by id;
if first.id then running_total=0;
running_Total + value;
run;
在PROC SQL中,这是不可能的,除非您有一个排序变量(您可以在其中执行类似的操作):
但是SAS没有按
划分的概念-SAS数据步骤远比这强大。我通常使用数据
步骤而不是过程sql
在SAS中运行总计。理论上,您可以使用procsql
和交叉连接来实现这一点,但这在现实世界中并不实用
步骤1:按ID值对数据进行排序
proc sort data=have;
by ID;
run;
第2步:使用sum语句计算运行总数
data want;
set have;
by ID;
New_Value+Value;
output;
if(last.ID) then New_Value = 0;
run;
解释
分组处理是SAS最强大的工具之一。当您按ID值排序并在数据步骤中对其使用by语句时,您将解锁两个新的特殊布尔变量:first.
和last..
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.ID
和last.ID
都是1
SAS中有一种特殊的语句,称为sum语句,用于保留和求和变量。SAS本身就是一种循环语言;每当它执行数据
步骤时,它只查看一条记录和一条记录。当它到达数据
步骤的底部并返回顶部时,b开始读取表中的下一条记录,并假设在读取或计算变量值之前,所有变量现在都已丢失。您实际输出的内容是称为程序数据向量的内容。在后台,这就是您正在操作的内容
默认情况下,只有在到达run
边界后,它才会输出到数据集。如果您明确告诉SAS要输出,则只有在您告诉它时,它才会输出。要累积一个变量,我们要告诉SAS四件事:
保留变量的上一个值(在读取新记录时,不要将其重置为
将变量添加到自身
将值添加到自身后的输出
在我输出并且这是一组ID变量中的最后一个观察值之后,将我的累积变量重置为0
要实现步骤1和2,您可以执行两个选项:
data want;
set have;
retain New_Value;
New_Value = sum(New_Value, Value);
或
请注意,第二个选项与第一个选项完全相同,但工作量较少。请将其视为一种快捷方式。这称为Sum语句。它看起来在语法上是错误的,但它是一种特殊且非常有用的情况
为了实现步骤3,我们只需告诉SAS在数据步骤结束后立即输出,而不是默认情况下在数据步骤结束时输出:
data want;
set have;
New_Value+Value;
output;
如果按原样运行上面的代码,New\u Value
将无限期地累加,直到它到达文件的最末尾。我们希望在它到达新的ID组后重置此值。我们使用“按组处理”解锁这两个布尔变量,以便在输出后的指定条件下将New\u 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
我们希望在新值
重置为0之前输出累积和
还有一些其他SAS过程可以用来做类似的事情,但它们是为特定情况而设计的。在这种情况下,您可以重新调整它们的用途来做您想做的事情,但最好在开始重新调整过程用途之前先学习数据步骤处理。Joe-您的答案无论出于何种原因都不起作用,但得到了正确的答案让我在正确的轨道上找到答案。谢谢
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;
还有一个选择:
data want;
do until (last.id);
set have;
by id;
new_value + value;
output;
end;
new_value = 0;
run;
我的数据步骤会产生与此完全相同的结果。您的工作比您需要的要努力一些-为什么有第二个变量?直觉上,您的应该会产生相同的结果-我提供的虚拟集会产生相同的结果-但我正在做的项目中的实际集不会产生相同的结果。对于为什么您的代码不能与我一起工作,我没有一个很好的答案在我的项目中,但由于某种原因,它没有产生所需的结果。听起来您可能有一个问题,即正在运行的total变量已经存在于数据集上(在本例中,have
)?这是唯一的区别,也是拥有第二个变量唯一会改变的事情。对于所描述的问题,这不是一个精心设计的解决方案。此外,如果您拥有SAS/ETS许可,请参阅此处发布的PROC EXPAND解决方案。
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;
data want;
do until (last.id);
set have;
by id;
new_value + value;
output;
end;
new_value = 0;
run;