【问题标题】:SAS union distinct records from datasets with similar namesSAS 联合来自具有相似名称的数据集的不同记录
【发布时间】:2021-03-03 07:13:01
【问题描述】:

我有大约 100 个大型数据集,我希望在每个数据集中提取不同的 ID 以垂直连接它们。数据集未排序,命名为 data_01 , data_02, data_03 ....data_100。

由于数据集都非常大,将它们放在一起而不减小大小是不可行的,运行数小时后连接甚至都没有移动。因此,我认为有必要在堆叠之前减少数据集,我在这里寻求一些帮助。

在通过 proc sql union 垂直连接所有数据集之前,我尝试创建一个宏来选择不同的 ID 并按 ID 对数值变量 cnt 求和。宏无法正常工作:

/*Get dataset names*/
proc sql noprint;
select  memname into :mylist separated by ' '
from dictionary.tables where libname= "mylib" and upcase(memname) like "DATA_%"
;
quit;

%put &mylist;

/*create union statements*/
%global nextdata;
%let nextdata =;
%macro combinedata(mylist);
  data _null_;
       datanum = countw("&mylist");
       call symput('Dataset', put(datanum, 10.));
  run;

   %do i = 1 %to  &Dataset ;
      data _null_;
          temp = scan("&mylist", &i);
          call symput("Dataname", strip(put(temp,$12.)));
      run;
       %put &Dataname;
       %put &Dataset;

        %if (&i=&Dataset) %then %do;
            %let nextdata = &nextdata.
                select id, sum(cnt)
                  from mylib.&&Dataname
                   group by id;
            %end;
        %else %do;
            %let nextdata = &nextdata.
               select id, sum(cnt)
                  from mylib.&&Dataname union
                   group by id;
         %end;

            %put nextdata = &nextdata;
    %end;


%mend combinedata;

%combinedata(&mylist);

/*execute from proc sql*/
proc sql;
    create table combined as (&nextdata);
quit;

我也尝试过使用 proc summary,但是没有足够的内存来运行以下代码:

data vneed / view=vneed;
  set data_: (keep=id cnt);
run;
proc summary data=vneed nway;
  class id;
  var cnt;
  output out=want (drop=_type_) sum=sumcnt;
run;

感谢任何帮助!

【问题讨论】:

  • 每个数据集有多大?你有多少内存可用?
  • 各个数据集是否已经按 ID 排序?或者如果没有排序,它们是否有 ID 索引?
  • @Tom 不,不幸的是它们没有按 ID 排序,否则我可以通过语句使用。 :(
  • ID是什么类型的变量?它包含多少不同的值?为什么不在 HASH 对象中构建数据?
  • @Tom ID 是数字,我不确定有多少不同的值,因为我从未成功堆叠所有数据集。会不会是 ID 是数字导致 proc 摘要内存不足?

标签: sql sas sas-macro


【解决方案1】:

如果 ID 值的数量合理,您应该能够使用哈希对象。

data _null_ ;
  if _n_=1 then do;
    dcl hash H (ordered: "A") ;
    h.definekey ("ID") ;
    h.definedata ("ID", "SUMCNT") ;
    h.definedone () ;
  end;
  set data_: (keep=id cnt) end=eof;
  if h.find() then sumcnt=.;
  sumcnt+cnt ;
  h.replace() ;
  if eof then h.output (dataset: "WANT") ;
run ;

如果 ID 值的数量太大而无法将摘要数据放入 HASH 对象中,您可以调整此代码以停止在某个合理数量的不同 ID 值处,以避免内存过载并将当前摘要写入实际的 SAS 数据集然后通过重新聚合中间数据集生成最终计数。但是此时您应该只使用我的其他答案并让 PROC SQL 创建中间摘要数据集。

【讨论】:

  • 它还在运行……已经一个多小时了
  • 内存不足,无法完成运行ERROR: Hash object added 23068656 items when memory failure occurred. FATAL: Insufficient memory to execute DATA step program. Aborted during the EXECUTION phase. ERROR: The SAS System stopped processing this step because of insufficient memory.
  • 您将需要转储并刷新散列对象,因为它变得太大。然后从聚合中重新聚合。
  • 我该如何编码?哈希对我来说很新。
【解决方案2】:

随时汇总数据,而不是尝试生成一个海量查询。然后重新聚合聚合。

proc sql ;
%do i = 1 %to  &Dataset ;
  %let dataname=mylib.%scan(&mylist,&i,%str( ));
  create table sum&i as 
   select id,sum(cnt) as cnt 
   from &dataname 
   group by id
   order by id
  ;
%end;
quit;

data want ;
  do until(last.id);
    set sum1 - sum&dataset ;
    by id;
    sumcnt+cnt;
  end;
  drop cnt;
run;

【讨论】:

  • 为超过 2000 万个 IDS 生成 100 + 一个文件的总和需要时间。仅读取 100 个文件需要时间。
猜你喜欢
  • 1970-01-01
  • 2013-06-06
  • 2014-07-13
  • 2021-10-30
  • 2015-06-15
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多