sas - variable - sql macro




是否有可能循環SAS數據集? (4)

我有60個SAS數據集,其中包含消費者的個人特徵,如id, gender, age, amountSpent, ....每個數據集只顯示一個時間段的數據(數據1是1月,數據2是2月...)。 由於尺寸和其他問題,我無法合併它們。

我如何編寫一個多重循環來遍歷每個數據集,做一些操作並將估計值保存到一個臨時文件。

SAS沒有for循環。 我怎麼用呢?


不需要宏,CALL EXECUTE將通過在SASHELP.VTABLE上構建一個查詢然後為每個實例執行一個數據步驟來處理libname或多個libnames中的每個數據集。 我通常剝離或壓縮數據集名稱,以確保空白不會導致問題,但會讓你自己添加。 您還可以對子集進行相關更改,並將結果附加到單個臨時數據集。

DATA WANT;
    SET SASHELP.VTABLE (KEEP = LIBNAME MEMNAME  WHERE = (LIBNAME = "MAPSSAS")) END=EOF;
    STR = COMPBL("DATA " || MEMNAME || "; SET " || LIBNAME || "." || MEMNAME ||";" );
    STR1
    CALL EXECUTE (STR);

    IF EOF THEN DO;
        STR = 'RUN;';
        CALL EXECUTE (STR);
    END;
RUN;

另一個選擇是創建一個包含所有數據集的視圖,這種方法不會產生任何數據大小問題(儘管我不知道在這裡提到的其他問題是否會成為問題)。 您需要一個相關數據集的列表,這些數據集可以從PROC SQL中的DICTIONARY.TABLES中獲得。

proc sql noprint;
select memname into :ds_list separated by ' '
from dictionary.tables
where libname='XXXXX';
quit;

data combined / view=combined;
set &ds_list;
run;

然後,只需對視圖運行摘要,所以不需要遍歷每個數據集。 我假設你的數據集有一個日期變量,否則你需要添加一些額外的功能(這適用於任何解決方案)。 看看這裡的表現與其他解決方案相比,會是一件有趣的事情。


這就是我在日常編程中如何解決這個問題的時候,需要根據數據反複調用宏。 這種方法同樣適用於許多數據集或來自一個數據集的許多變量或來自一個數據集的許多不同的宏調用 - 無論它們是哪一個,都可以簡單地創建一個數據集,其中包含不同的信息並以此方式調用。

這種方法將Shorack解決方案的元素與user2337871和Neil結合起來。 為什麼做不同呢?

  • 宏應該用參數調用,不包含它內部的參數定義。 這使得它在將來的使用中更加靈活(例如, dataset_list數據集可能是不同的)。
  • 具有基於名稱數據集的調用靈活性,而不需要宏調用宏
  • 將代碼移除到宏中(而不是在call execute或其他調用方法內部)使得它更易於閱讀。
  • call execute可能有一些缺點取決於你正在做的操作(與宏可變時間有關)

假設您正在執行PROC MEANS,然後將其附加到主數據集。 雖然這實際上是一個非常緩慢和煩人的方式(而不是將它們組合在一起並使用BY,或者甚至將ODS OUTPUT與非組合數據集一起使用),但我們將假設您的實際任務更為複雜。

%macro do_my_stuff(dataset=);
proc means data=&dataset noprint;
var count;
output out=dsn_&dataset. mean=;
run;

proc append base=results data=dsn_&dataset. force;
run;
%mend do_my_Stuff;

proc sql;
select cats('%do_my_stuff(dataset=',name,')') into :stufflist separated by ' '
from dictionary.tables
where memname='WORK';
quit;

&stufflist;

您可以在proc sql中的where語句中添加其他條件,或使用CALL EXECUTE或多個不同的選項來調用該條件。 您也可以使用自製的數據集與數據集名稱(甚至變量作為另一列和宏參數,如果感興趣的變量(數據集)變化)。


但是薩斯在宏觀循環中確實有一個做。 所以基本上你需要3件事:1.在某種程度上,你的數據集列表。 2.一個循環遍歷此列表的宏。 3.你想做的事情。

例如,讓我們假設您有一個數據集WORK.DATASET_LIST,其中包含要循環訪問的每個數據集的變量庫(libname)和變量成員(數據集名稱)。

那麼你可以這樣做:

%macro loopOverDatasets();
    /*imho good practice to declare macro variables of a macro locally*/
    %local datasetCount iter inLibref inMember;

    /*get number of datasets*/
    proc sql noprint;
        select count(*)
         into :datasetCount
        from WORK.DATASET_LIST;
    quit;

    /*initiate loop*/
    %let iter=1;
    %do %while (&iter.<= &datasetCount.);
        /*get libref and dataset name for dataset you will work on during this iteration*/
        data _NULL_;
            set WORK.DATASET_LIST (firstobs=&iter. obs=&iter.); *only read 1 record;
            *write the libname and dataset name to the macro variables;
            call symput("inLibref",strip(libname));
            call symput("inMember",strip(member));
            *NOTE: i am always mortified by the chance of trailing blanks torpedoing my code, hence the strip function;
        run;

        /*now you can apply your logic to the dataset*/
        data &inLibref..&inMember.; *assuming you want to apply the changes to the dataset itself;
            set &inLibref..&inMember.;
            /*** INSERT YOUR LOGIC HERE ***/
        run;

        /*** ANY OTHER PROCS/DATA STEPS ***/
        /*just remember to use &inLibref..&inMember. to refer to the current dataset*/

        /*increment the iterator of the loop*/
        %let iter=%eval(&iter.+1);
    %end;
%mend;

/*call the macro*/
%loopOverDatasets()

這是這個想法。 也許你想以不同的方式收集數據集的列表。 例如,包含它們的宏變量。 在這種情況下,您必須使用循環中的%scan函數來選擇一個數據集。 或者也許在命名中有邏輯,例如dataset1,dataset2,dataset3 ...,在這種情況下,您可以簡單地使用&iter。 宏變量。