问题描述
我想计算按另一列分组的累积最大值.
假设我有这些数据:
数据有;输入grp $数字;数据线;一个 3b 4一个 5b 2一个 1b 8;
我想要的输出是:
需要的数据;输入 grp $ cummax;一个 3b 4一个 5b 4一个 5b 8;
我的真实案例将涉及多个分组列 + 过滤器,理想情况下,此累积最大值将同时在多个列上计算.
我主要关心的是计算效率,因为我将在包含 10 到数亿行的表上运行它.欢迎使用 Proc SQL 或原生 SAS.
如有必要,行可能会被打乱.
系统信息
proc product_status;run;
对于基本 SAS 软件 ...自定义版本信息:9.3_M2镜像版本信息:9.03.01M2P080112对于 SAS/STAT ...自定义版本信息:12.1镜像版本信息:9.03.01M0P081512对于 SAS/图形 ...自定义版本信息:9.3_M2对于 SAS/连接...自定义版本信息:9.3_M2对于 SAS OLAP 服务器...自定义版本信息:9.3_M1对于 SAS 企业矿工...自定义版本信息:12.1镜像版本信息:9.03.01M0P081512对于 SAS 集成技术...自定义版本信息:9.3_M2对于到 Oracle 的 SAS/ACCESS 接口...自定义版本信息:9.3_M1对于 PC 文件的 SAS/ACCESS 接口...自定义版本信息:9.3_M2
proc setinit;run;
产品有效期:---基础 SAS 软件 31JUL2018---SAS/STAT 31JUL2018---SAS/图表 31JUL2018---SAS/连接 2018 年 7 月 31 日---SAS OLAP 服务器 31JUL2018---SAS企业矿工 31JUL2018---MDDB Server 常用产品 31JUL2018---SAS 集成技术 31JUL2018---SAS企业矿机服务器 31JUL2018---SAS企业矿工客户端31JUL2018---未使用的 OLAP 插槽 31JUL2018---SAS企业指南31JUL2018--- SAS/ACCESS 接口到 Oracle 31JUL2018--- SAS/ACCESS 接口到 PC 文件 31JUL2018---适用于 Informatica 的 SAS 元数据桥 31JUL2018---适用于 Microsoft SQL Server 的 SAS 元数据桥 31JUL2018---适用于 Oracle 的 SAS 元数据桥 31JUL2018---用于本地访问的 SAS 工作区服务器 31JUL2018---用于企业访问的 SAS 工作区服务器 31JUL2018---SAS 表服务器 31JUL2018---DataFlux Trans DB 驱动程序 31JUL2018---SAS 框架数据服务器 31JUL2018---Microsoft Excel 的 SAS 插件 31JUL2018---适用于 Microsoft Outlook 的 SAS 插件 31JUL2018---Microsoft PowerPoint 的 SAS 插件 31JUL2018---Microsoft Word 的 SAS 插件 31JUL2018
使用 HASH
对象来存储每个变量和组组合的最大值.这将允许您单次通过您的数据集并编写一些您可以根据组和变量的数量进行扩展的代码.
这不需要在大型数据集上代价高昂的排序.
测试数据
数据示例;格式 grp1-grp5 $1.;数组 grp[5];数组 val[5];行=1 到 1000000;做 i=1 到 5;r = ceil(ranuni(1)*5);grp[i] = substr("ABCDE",r,1);结尾;做 j=1 到 5;val[j] = 10*rannor(1);结尾;输出;结尾;保持 grp: val:;跑;
计算累积最大值的数据步
需要的数据;树立榜样;数组 val[5];数组最大值[5];如果 _n_ = 1 则执行;声明哈希 mx();rc = mx.defineKey('grp1','grp2','grp3','grp4','grp5');rc = mx.definedata('max1','max2','max3','max4','max5');rc = mx.definedone();结尾;rc = mx.find();/*这个组合没有最大值——添加它*/如果 rc 则执行;做 i=1 到 5;最大[i] = 值[i];结尾;结尾;/*更新最大值*/做 i=1 到 5;如果 val[i] >最大[i] 然后最大[i] = 值[i];结尾;/*更新哈希*/rc = mx.replace();删除 rc i;n = _n_;/*这是为了测试*/跑;
使用测试变量n
,我们可以对保持原始顺序的组进行排序,看看它是否有效.(提示,确实如此).
proc sort data=want;通过 grp: n;跑;
I want to compute a cumulative max grouped by another column.
Say I have this data:
data have;
input grp $ number;
datalines;
a 3
b 4
a 5
b 2
a 1
b 8
;
My desired output would be:
data want;
input grp $ cummax;
a 3
b 4
a 5
b 4
a 5
b 8
;
My real case will involve several grouping columns + filters, and ideally this cumulative max would be computed on several columns at the same time.
My main concern is computational efficiency as I'll be running this on tables of ten to hundred millions of rows. Proc SQL or native SAS are both welcome.
Rows might be shuffled if necessary.
System Info
proc product_status;run;
proc setinit;run;
Use a HASH
object to store the max for each variable and group combination. This will allow you to single pass through your data set and code something that you can scale for the number of groups and variables.
This does not require a sort which can be costly on a large data set.
Test Data
data example;
format grp1-grp5 $1.;
array grp[5];
array val[5];
do rows=1 to 1000000;
do i=1 to 5;
r = ceil(ranuni(1)*5);
grp[i] = substr("ABCDE",r,1);
end;
do j=1 to 5;
val[j] = 10*rannor(1);
end;
output;
end;
keep grp: val:;
run;
Data Step to compute the cumulative max
data want;
set example;
array val[5];
array max[5];
if _n_ = 1 then do;
declare hash mx();
rc = mx.defineKey('grp1','grp2','grp3','grp4','grp5');
rc = mx.definedata('max1','max2','max3','max4','max5');
rc = mx.definedone();
end;
rc = mx.find();
/*No Max for this combination -- add it*/
if rc then do;
do i=1 to 5;
max[i] = val[i];
end;
end;
/*Update Max Values*/
do i=1 to 5;
if val[i] > max[i] then
max[i] = val[i];
end;
/*Update Hash*/
rc = mx.replace();
drop rc i;
n = _n_; /*This is for testing*/
run;
Using that testing variable n
, we can sort the groups keeping the original order and see if it worked. (hint, it did).
proc sort data=want;
by grp: n;
run;
这篇关于SAS 或 PROC SQL 中按组的累积最大值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!