web-dev-qa-db-ja.com

SASデータセットをループすることは可能ですか?

id, gender, age, amountSpent, ....などの消費者の個々の特性に関するデータを含む60のsasデータセットがあります。各データセットは1つの期間のデータのみを表示します(data1は1月、data2は2月...)。サイズやその他の問題のため、それらをマージできません。

各データセットを調べ、いくつかの操作を行い、推定値を一時ファイルに保存するための複数のループを作成するにはどうすればよいですか。

SASにはforループがありません。 doを使用するにはどうすればよいですか?

10
Buras

しかし、sasにはdowhileマクロループがあります。したがって、基本的に3つのものが必要です。1。何らかの方法で、データセットのリスト。 2.このリストをループするマクロ。 3.やりたいこと。

たとえば、ループするすべてのデータセットの変数ライブラリ(libname)と変数メンバー(dataset name)を含むデータセットWORK.DATASET_LISTがあると仮定します。

次に、次のことができます。

%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を使用するだけで済みます。マクロ変数。

7
mvherweg

これが、データに基づいてマクロを繰り返し呼び出す必要がある日常のプログラミングでこの問題を解決する方法です。このアプローチは、1つのデータセットからの多くのデータセット、多くの変数、または1つのデータセットからの多くの異なるマクロ呼び出しで同様に機能します。どちらの場合でも、さまざまな情報を使用してデータセットを作成し、このように呼び出します。

このアプローチは、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、またはいくつかの異なるオプションを使用してそれを呼び出すことができます。データセット名を使用して自作のデータセットを使用することもできます(対象の変数がデータセットによって異なる場合は、変数を別の列およびマクロパラメーターとして使用することもできます)。

7
Joe

別のオプションは、すべてのデータセットを組み合わせたビューを作成することです。このアプローチではデータサイズの問題は発生しません(ただし、参照している他の問題がここで問題になるかどうかはわかりません)。関連するデータセットのリストが必要になります。これは、PROCSQLの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;

次に、ビューに対してサマリーを実行するだけなので、各データセットをループする必要はありません。データセットには日付変数があると思います。そうでない場合は、いくつかの追加機能を追加する必要があります(これはすべてのソリューションに適用されます)。ここで他のソリューションと比較して、これがどのように機能するかを確認するのは興味深いことです。

7
Longfish

マクロは必要ありません。CALLEXECUTEは、SASHELP.VTABLEでクエリを作成し、インスタンスごとにデータステップを実行するだけで、libnameまたは複数のlibname内のすべてのデータセットを処理します。私は通常、データセット名を削除または圧縮して、空白が問題を引き起こさないようにしますが、自分で追加することもできます。サブセットに関連する変更を加えて、結果を単一の一時データセットに追加することもできます。

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;
3
user2337871

私の頼りになる答えはマクロです。

%MACRO process_datasets(mdataset);
     data &mdataset.;
     set &mdataset.;
     if age >= '50' then discountRate = .2;
     *whatever else you need here;
     run;

     data _null_;
       file 'tmp.csv' mod dsd dlm=',';  *I'm assuming you're saving everything to the same file;
       set &mdataset.;
       put (_all_) (+0);
     run;

%MEND process_datasets;

次に、別のマクロループから呼び出すことができます。

%MACRO loop_through_all;
    %DO i = 1 to 60;
       %process_datasets(data&i.);
     %END;
%MEND loop_through_all;

%loop_through_all;
3
Neil Neyman