这个proc sql的数据步骤相当于什么?
proc sql;
create table issues2 as(
select request,
area,
sum(issue_count) as issue_count,
sum(resolved_count) as resolved_count
from
issues1
group by request, area
);
答案 0 :(得分:3)
PROC MEANS / SUMMARY更好,但如果相关,则实际数据步骤解决方案如下。基本上您只需将计数器重置为first.<var>
上的0并输出last.<var>
,其中<var>
是by
组中的最后一个变量。
注意:这假设数据已排序by request area
。如果不是,请对其进行排序。
data issues2(rename=(issue_count_sum=issue_count resolved_count_sum=resolved_count) drop=issue_count resolved_count);
set issues1;
by request area;
if first.area then do;
issue_count_sum=0;
resolved_count_sum=0;
end;
issue_count_sum+issue_count;
resolved_count_sum+resolved_count;
if last.area then output;
run;
答案 1 :(得分:2)
您尝试做的功能相当于以下内容:
data _null_;
set issues1(rename=(issue_count=_issue_count
resolved_count=_resolved_count)) end=done;
if _n_=1 then do;
declare hash total_issues();
total_issues.defineKey("request", "area");
total_issues.defineData("request", "area", "issue_count", "resolved_count");
total_issues.defineDone();
end;
if total_issues.find() ne 0 then do;
issue_count = _issue_count;
resolved_count = _resolved_count;
end;
else do;
issue_count + _issue_count;
resolved_count + _resolved_count;
end;
total_issues.replace();
if done then total_issues.output(dataset: "issues2");
run;
此方法不要求您对数据集进行预排序。我想看看你使用不同方法可以获得什么样的性能,所以我对74M行数据集做了一些测试。我得到了以下运行时间(结果可能会有所不同):
未排序的数据集:
Proc SQL
- 12.18秒Data
使用哈希对象方法(上图) - 26.68秒Proc Means
使用class
声明(nway) - 5.13秒排序数据集(36.94秒进行过程排序):
Proc SQL
- 10.82秒Proc Means
使用by
声明 - 9.31秒Proc Means
使用class
声明(nway) - 6.07秒Data
使用by
语句(我使用了Joe的回答代码) - 8.97秒正如您所看到的,我不推荐使用上面显示的哈希对象方法的数据步骤,因为它花了两倍于proc sql。
我不确定为什么proc means
使用by
语句花费的时间比使用proc means
语句class
更长,但我尝试了一堆不同的语句数据集并看到了运行时的类似差异(我在Linux 64上使用SAS 9.3)。
需要记住的是,这些运行时可能与您的情况完全不同,但我建议使用以下代码进行求和:
proc means data=issues1 noprint nway;
class request area;
var issue_count resolved_count;
output out=issues2(drop=_:) sum=;
run;
答案 2 :(得分:1)
我认为,在数据步骤中完成这一点很麻烦 - 在by
变量的每个级别对变量进行求和和重置都可行。哈希对象也可以做到这一点。
也许最简单的非Proc SQL方法是使用Proc Summary: -
proc summary data = issues1 nway missing;
class request area;
var issue_count resolved_count;
output out = issues2 sum(issue_count) = issue_count sum(resolved_count) = resolved_count ;
run;
答案 3 :(得分:1)
这是临时数组方法。这是最简单的&#34;其中,对请求和区域值做出一些假设;如果这些假设是错误的,因为它们通常是真实的数据,它可能不是那么容易。请注意,虽然在下面数据确实正好进行排序,但我并不依赖它进行排序,并且该过程不会从排序中获得任何好处。
data issues1;
do request=1 to 1e5;
do area = 1 to 7;
do issueNum = 1 to 1e2;
issue_count = floor(rand('Uniform')*7);
resolved_count = floor(rand('Uniform')*issue_count);
output;
end;
end;
end;
run;
data issues2;
set issues1 end=done;
array ra_issue[1100000] _temporary_;
array ra_resolved[1100000] _temporary_;
*array index = request||area, so request 9549 area 6 = 95496.;
ra_issue[input(cats(request,area),best7.)] + issue_count;
ra_resolved[input(cats(request,area),best7.)] + resolved_count;
if done then do;
do _t = 1 to dim(ra_issue);
if not missing(ra_issue[_t]) then do;
request = floor(_t/10);
area = mod(_t,10);
issue_count=ra_issue[_t];
resolved_count=ra_resolved[_t];
output;
keep request area issue_count resolved_count;
end;
end;
end;
run;
考虑到我开始使用的简单数据,它与CLASS的PROC MEANS相当。如果你不能从区域和请求的组合中简单地生成一个密钥(例如,如果它们是字符变量),你将不得不存储另一个名称到密钥关系的数组,这将使它成为一个如果有很多组合,那么速度会慢很多(尽管组合相对较少,但并不一定都那么糟糕)。如果由于某种原因你在生产中这样做,我会首先创建一个独特的请求+区域组合表,创建一个格式和一个Informat来来回转换来自一个独特的键(这应该非常快,并给你一个可靠的索引),然后使用那种格式/信息而不是我在这里做的猫/分模数来做到这一点。