将大型SAS数据集拆分为较小的数据集

时间:2014-01-29 18:52:20

标签: macros split sas

我需要一些帮助,将大型SAS数据集拆分为较小的数据集。

每个月我都会有一个包含几百万条记录的数据集。这个数字每个月都有所不同。我需要将此数据集拆分为多个较小的数据集,每个数据集包含250,000条记录。例如,如果我在原始数据集中有1,050,000条记录,那么我需要最终结果是包含250,000条记录的4个数据集和包含50,000条记录的1个数据集。

从我一直看来,它似乎需要使用宏。不幸的是,我对SAS很熟悉(不熟悉使用宏)并且没有太多时间来完成这项工作。任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:3)

基于乔的回答,也许你可以尝试这样的事情:

%MACRO SPLIT(DATASET);

%LET DATASET_ID = %SYSFUNC(OPEN(&DATASET.));
%LET NOBS = %SYSFUNC(ATTRN(&DATASET__ID., NLOBS));
%LET NB_DATASETS = %SYSEVALF(&NOBS. / 250000, CEIL);

DATA 
  %DO I=1 %TO &NB_DATASETS.;
    WANT&I. 
  %END;;

  SET WANT;

  %DO I=1 %TO &NB_DATASETS.;

    %IF &I. > 1 %THEN %DO; ELSE %END; IF _N_ LE 2.5E5 * &I. THEN OUTPUT WANT&I.;

  %END;
RUN;
%MEND SPLIT;    

答案 1 :(得分:1)

如果您不介意要求可能不存在的数据集,并且对事物有合理的约束,那么您可以完全不使用宏。

data want1 want2 want3 want4 want5 want6 want7 want8 want9;
if _n_ le 2.5e5 then output want1;
else if _n_ le 5e5 then output want2;
else if _n_ le 7.5e5 then output want3;
... etc....
run;

宏可以使编程更有效,阅读更清晰,但不会改变它实际运行的方式。

答案 2 :(得分:1)

您可以使用CALL EXECUTE()在没有宏的情况下执行此操作。它会创建SAS代码作为文本字符串,然后在“手动编写”代码完成后执行它。

data _null_;
    if 0 then set have nobs=n;
    do i=1 to ceil(n/250000);
        call execute (cats("data want",i)||";");
        call execute ("set have(firstobs="||(i-1)*250000+1||" obs="||i*250000||");");
        call execute ("run;");
    end;
run;

答案 3 :(得分:0)

Google的第一个结果来自SAS国际用户组(SUGI) 这些人是你的朋友。

文章在这里: http://www2.sas.com/proceedings/sugi27/p083-27.pdf

代码是:

%macro split(ndsn=2); 
data %do i = 1 %to &ndsn.; dsn&i. %end; ; 
 retain x; 
 set orig nobs=nobs; 
 if _n_ eq 1 
 then do; 
 if mod(nobs,&ndsn.) eq 0 
 then x=int(nobs/&ndsn.); 
 else x=int(nobs/&ndsn.)+1; 
 end; 
 if _n_ le x then output dsn1; 
 %do i = 2 %to &ndsn.; 
 else if _n_ le (&i.*x) 
 then output dsn&i.; 
 %end; 
 run; 
%mend split; 

%split(ndsn=10);

您需要做的就是替换“%split(ndsn = 10);”中的10位数字。用你需要的号码。 在第4行“set orig nobs = nobs;”中,只需用您的数据集名称替换orig。

嘿presto!

答案 4 :(得分:0)

一个更有效的选项,如果你有足够的空间来存储一个的较小数据集,那么这是一个哈希解决方案。这是一个基本上使用您在问题中描述的内容的示例:

data in_data;
  do recid = 1 to 1.000001e7;
    datavar = 1;
    output;
  end;
run;


data _null_;
  if 0 then set in_data;
  declare hash h_out();
  h_out.defineKey('_n_');
  h_out.defineData('recid','datavar');
  h_out.defineDone();

  do filenum = 1 by 1 until (eof);
    do _n_ = 1 to 250000 until (eof);
      set in_data end=eof;
      h_out.add();
    end;
    h_out.output(dataset:cats('file_',filenum));
    h_out.clear();
  end;
  stop;
run;

我们使用适当的参数定义哈希对象,并简单地告诉它输出每250k记录并清除它。我们也可以在这里进行散列哈希,特别是如果它不是"每250k记录"但是其他一些标准驱动了事情,但是你必须在记忆中记录所有记录,而不仅仅是250k记录。

另请注意,我们可以在不明确指定变量的情况下执行此操作,但需要在数据集上使用有用的ID:

data _null_;
  if 0 then set in_data;
  declare hash h_out(dataset:'in_data(obs=0)');
  h_out.defineKey('recid');
  h_out.defineData(all:'y');
  h_out.defineDone();

  do filenum = 1 by 1 until (eof);
    do _n_ = 1 to 250000 until (eof);
      set in_data end=eof;
      h_out.add();
    end;
    h_out.output(dataset:cats('file_',filenum));
    h_out.clear();
  end;
  stop;
run;

由于在构造函数上使用_n_选项(dataset功能所必需的),我们不能再使用all:'y'作为哈希ID,我们必须拥有记录ID。希望有这样一个变量,或者可以添加一个视图。

答案 5 :(得分:0)

这是一种基本方法。这需要手动调整间隔,但很容易理解。

* split data;
data output1;
set df;
if 1 <= _N_ < 5 then output;
run;


data output2;
set df;
if 5 <= _N_ < 10 then output;
run;


data output3;
set df;
if 10 <= _N_ < 15 then output;
run;


data output4;
set df;
if 15 <= _N_ < 22 then output;
run;