/*
データを指定した個数になるべく同じ大きさで分割するマクロです。
このプログラムのポイントは、DATAステップを1回だけ回す点です。
マクロを一度サブミットしてから、利用できます。
使い方は、こんな感じです。
(使用例)
ユーザー定義のライブラリuserdataに存在するSASデータセットtest1を5分割します。
出力データセットはライブラリuserdataに保存され、splitdata1,splitdata2,…,splitdata5
という名前になります。データ分割の際に使用するランダムシードは123です。
%partition1(data=userdata.test1, outlib=userdata, outdataprefix=splitdata,
n= 5, seed=123)
*/
%macro partition1(data=_last_,outlib=WORK,outdataprefix=OUT,n=2,seed=0);
%* data=で指定したSASデータセットの存在をチェックする;
%if %sysfunc(exist(&data))=0 %then %do;
%put ERROR: 指定したデータセットが存在しません。分割データセットは作成されませんでした。;
%goto last;
%end;
%* outlib=で指定したSASライブラリの存在をチェックする;
%if %sysfunc(libref(&outlib)) ne 0 %then %do;
%put ERROR: 指定したライブラリが存在しません。分割データセットは作成されませんでした。;
%goto last;
%end;
%* n=で指定する分割数は2以上;
%if %sysevalf(&n-2<0) %then %do;
%put ERROR: n=で指定する分割数は2以上の整数でなくてはなりません。分割データセットは作成されませんでした。;
%goto last;
%end;
%* n=で指定する分割数は正の整数;
%if %sysevalf(&n-%sysfunc(int(&n))) ne 0 %then %do;
%let n=%sysfunc(int(&n));
%put WARNING: n=で指定した数値が正の整数ではなかったため、小数点以下は切り捨てられました。;
%end;
%* 入力データセットのオブザベーション数を取得;
options nonotes;
%let obs=0;
data _null_;
set &data nobs=n;
call symput('obs',left(put(n,best.)));
stop;
run;
options notes;
%* 入力データセットのオブザベーションが1以下のときの処理;
%if &obs<2 %then %do;
%put WARNING: 入力データセットのオブザベーション数が1以下です。分割データセットは作成されませんでした。;
%goto last;
%end;
%* オブザベーション数が分割数よりも小さなときの処理;
%if &n>&obs %then %do;
%put WARNING: 入力データセットのオブザベーション数は、指定した分割数より小さくなっています。
1オブザベーションからなるデータセットが%trim(&obs)個作成されます。;
%let n=&obs;
%end;
%* 分割された各データセットのオブザベーション数を定め、マクロ変数initialに格納;
%let __mod=%sysfunc(mod(&obs,&n));
%let __int=%sysfunc(int(&obs/&n));
%let initial=;
%do i=1 %to &__mod;
%let initial=&initial %eval(&i*(&__int+1));
%end;
%do i=&__mod+1 %to &n-1;
%let initial=&initial %eval(&i*&__int+&__mod);
%end;
%*分割データセットの作成;
data
%do i=1 %to &n;
&outlib..&outdataprefix.&i
%end;
;
call streaminit(&seed);
array __temp{%eval(&n-1)} _temporary_ (&initial);
set &data;
__random=(&obs+1-_n_)*rand('uniform');
%do i=1 %to &n-1;
if __random<=__temp{&i} then do;
__ii=&i;
output &outlib..&outdataprefix.&i;
end;
else
%end;
do;
__ii=&n;
output &outlib..&outdataprefix.&n;
end;
do __i=__ii to &n-1;
__temp{__i}=__temp{__i}+(-1);
end;
drop __random __i __ii;
run;
%*設定に問題があれば、ここに飛ぶ;
%last :;
%mend;