2

与此 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 
                         );
4

4 回答 4

3

PROC MEANS/SUMMARY 更好,但如果它是相关的,实际的数据步骤解决方案如下。基本上,您只需将计数器重置为 0 onfirst.<var>并输出 on 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;
于 2014-04-16T18:05:44.843 回答
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 秒
  • DataStep With Hash Object Method(上图) - 26.68 秒
  • Proc Means使用class语句 (nway) - 5.13 秒

排序数据集(36.94 秒进行 proc 排序):

  • Proc SQL- 10.82 秒
  • Proc Means使用by语句 - 9.31 秒
  • Proc Means使用class语句 (nway) - 6.07 秒
  • DataStep usingby语句(我使用了 Joe 回答中的代码) - 8.97 秒

如您所见,我不建议将数据步骤与上面显示的哈希对象方法一起使用,因为它花费的时间是 proc sql 的两倍。

我不确定为什么proc means使用语句比使用by语句花费更长的时间,但是我在一堆不同的数据集上尝试了这个,并看到了运行时的类似差异(我在 Linux 64 上使用 SAS 9.3)。proc meansclass

需要记住的是,这些运行时对于您的情况可能完全不同,但我建议使用以下代码进行求和:

proc means data=issues1 noprint nway;
  class request area;
  var issue_count resolved_count;
  output out=issues2(drop=_:) sum=;
run;
于 2014-04-16T21:11:05.680 回答
1

这是临时数组方法。这是其中“最简单的”,对请求和面积值做了一些假设;如果这些假设是错误的,因为它们通常存在于真实数据中,那么可能就没有这么简单了。请注意,虽然在下面的数据确实被排序,但我不依赖它被排序,并且该过程不会从排序中获得任何优势。

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 相当。如果您不能从区域和请求的组合中轻松生成键(例如,如果它们是字符变量),则必须存储另一个名称到键关系的数组,这会使其速度慢很多如果有很多组合(尽管如果组合相对较少,则不一定那么糟糕)。如果出于某种原因你在生产中这样做,我会首先创建一个唯一请求+区域组合的表,创建一个格式和一个信息来从一个唯一键来回转换(这应该非常快并且给你一个可靠的index),然后使用该格式/信息而不是我在这里所做的猫/除法模数来执行此操作。

于 2014-04-16T21:41:09.050 回答
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;
于 2014-04-16T18:01:08.243 回答