簡體   English   中英

將大型SAS數據集拆分為較小的數據集

[英]Split large SAS dataset into smaller datasets

我需要一些幫助,將大型SAS數據集拆分為較小的數據集。

每個月我都會有一個包含幾百萬條記錄的數據集。 這個數字每個月都有所不同。 我需要將此數據集拆分為多個較小的數據集,每個數據集包含250,000條記錄。 例如,如果我在原始數據集中有1,050,000條記錄,那么我需要最終結果是包含250,000條記錄的4個數據集和包含50,000條記錄的1個數據集。

從我一直看來,它似乎需要使用宏。 不幸的是,我對SAS很熟悉(不熟悉使用宏)並且沒有太多時間來完成這項工作。 任何幫助將不勝感激。

基於喬的回答,也許你可以嘗試這樣的事情:

%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;    

如果你不介意要求可能不存在的數據集,並且對事物有合理的約束,你可以在沒有宏的情況下完成它。

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;

宏可以使編程更加高效,閱讀更清晰,但不會改變它實際運行的方式。

你可以使用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;

一個更有效的選擇,如果你有足夠的空間存儲一個較小的數據集,是一個哈希解決方案。 這是一個基本上使用您在問題中描述的內容的示例:

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_作為哈希ID,因為在構造函數上使用了dataset選項( all:'y'功能所必需的),我們必須有一個記錄ID。 希望有這樣一個變量,或者可以添加一個視圖。

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!

這是一種基本方法。 這需要手動調整間隔,但很容易理解。

* 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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM