SAS 中的分区 运行 总数
Partitioned Running Totals in SAS
如何为现有数据集创建一个新列,该数据集是 运行 个现有列的总和 - 按某个标识符分区?
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 中显然不支持该语法。
如果可能的话,我想在 PROC SQL 中完成这个(我对 SQL 的经验比 SAS 编码要多得多)。
谢谢!
麦克。
在数据步骤中,这是通过 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 数据步骤比那个更强大。
我通常使用 data
步骤而不是 proc sql
在 SAS 中进行 运行ning 总计。理论上您可以使用 proc sql
和交叉连接来做到这一点,但这在现实世界中不太实用。
第 1 步:按您的 ID 值对数据进行排序
proc sort data=have;
by ID;
run;
第 2 步:使用求和语句
计算 运行ning 总数
data want;
set have;
by ID;
New_Value+Value;
output;
if(last.ID) then New_Value = 0;
run;
说明
分组处理是 SAS 最强大的工具之一。当您按 ID 值排序并在数据步骤中对其使用 by 语句时,您解锁了两个新的特殊布尔变量: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.ID
和 last.ID
都会是 1。
SAS 中有一个特殊的语句称为 sum 语句,它既可以保留变量又可以对变量求和。 SAS 本质上是一种循环语言;每当它 运行 通过 data
步骤时,它只查看一条记录和一条记录。当它到达 data
步骤的底部并回到顶部时,开始读取 table 中的下一条记录,并假定所有变量现在再次丢失,直到它读取或计算变量' 价值。您真正输出的是称为程序数据向量的内容。在后台,这就是你正在操纵的东西。
默认情况下,它只有在达到run
边界后才会输出到数据集。如果您明确告诉 SAS 输出,它只会在您告诉它时输出。要累积一个变量,我们要告诉 SAS 四件事:
- 保留变量的前一个值(读取新记录时不要将其重置为丢失)
- 将变量添加到自身
- 我给自己加值后的输出
- 在我输出并且它是一组ID变量中的最后一个观察值后,将我的累积变量重置为0
要实现第 1 步和第 2 步,您可以执行两个选项:
data want;
set have;
retain New_Value;
New_Value = sum(New_Value, Value);
或
data want;
set have;
New_Value+Value;
请注意,第二个选项与第一个选项完全相同,但工作量更少。将其视为捷径。这称为求和语句。看起来它在语法上是错误的,但它是一个特殊且非常有用的案例。
为了实现第 3 步,我们只需告诉 SAS 在之后立即输出,而不是默认在数据步骤结束时输出:
data want;
set have;
New_Value+Value;
output;
如果您按原样 运行 上面的代码,New_Value
将无限期地累加,直到到达文件的末尾。一旦到达新的 ID 组,我们希望重置此值。我们使用分组处理来解锁这两个布尔变量,以便在我们输出后的指定条件下将 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
步骤处理,然后再进入过程重新调整用途。
乔 - 无论出于何种原因,你的回答都没有奏效,但让我走上了正确的轨道来弄清楚。谢谢!
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;
如何为现有数据集创建一个新列,该数据集是 运行 个现有列的总和 - 按某个标识符分区?
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 中显然不支持该语法。
如果可能的话,我想在 PROC SQL 中完成这个(我对 SQL 的经验比 SAS 编码要多得多)。
谢谢!
麦克。
在数据步骤中,这是通过 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 数据步骤比那个更强大。
我通常使用 data
步骤而不是 proc sql
在 SAS 中进行 运行ning 总计。理论上您可以使用 proc sql
和交叉连接来做到这一点,但这在现实世界中不太实用。
第 1 步:按您的 ID 值对数据进行排序
proc sort data=have;
by ID;
run;
第 2 步:使用求和语句
计算 运行ning 总数data want;
set have;
by ID;
New_Value+Value;
output;
if(last.ID) then New_Value = 0;
run;
说明
分组处理是 SAS 最强大的工具之一。当您按 ID 值排序并在数据步骤中对其使用 by 语句时,您解锁了两个新的特殊布尔变量: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.ID
和 last.ID
都会是 1。
SAS 中有一个特殊的语句称为 sum 语句,它既可以保留变量又可以对变量求和。 SAS 本质上是一种循环语言;每当它 运行 通过 data
步骤时,它只查看一条记录和一条记录。当它到达 data
步骤的底部并回到顶部时,开始读取 table 中的下一条记录,并假定所有变量现在再次丢失,直到它读取或计算变量' 价值。您真正输出的是称为程序数据向量的内容。在后台,这就是你正在操纵的东西。
默认情况下,它只有在达到run
边界后才会输出到数据集。如果您明确告诉 SAS 输出,它只会在您告诉它时输出。要累积一个变量,我们要告诉 SAS 四件事:
- 保留变量的前一个值(读取新记录时不要将其重置为丢失)
- 将变量添加到自身
- 我给自己加值后的输出
- 在我输出并且它是一组ID变量中的最后一个观察值后,将我的累积变量重置为0
要实现第 1 步和第 2 步,您可以执行两个选项:
data want;
set have;
retain New_Value;
New_Value = sum(New_Value, Value);
或
data want;
set have;
New_Value+Value;
请注意,第二个选项与第一个选项完全相同,但工作量更少。将其视为捷径。这称为求和语句。看起来它在语法上是错误的,但它是一个特殊且非常有用的案例。
为了实现第 3 步,我们只需告诉 SAS 在之后立即输出,而不是默认在数据步骤结束时输出:
data want;
set have;
New_Value+Value;
output;
如果您按原样 运行 上面的代码,New_Value
将无限期地累加,直到到达文件的末尾。一旦到达新的 ID 组,我们希望重置此值。我们使用分组处理来解锁这两个布尔变量,以便在我们输出后的指定条件下将 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
步骤处理,然后再进入过程重新调整用途。
乔 - 无论出于何种原因,你的回答都没有奏效,但让我走上了正确的轨道来弄清楚。谢谢!
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;