我有60个sas数据集,其中包含有关消费者个人特征的数据,例如id, gender, age, amountSpent, ....
每个数据集仅显示一个时间段的数据(data1为Jan,data2为Feb ...)。由于尺寸和其他一些问题,我无法合并它们。
如何编写多循环来遍历每个数据集,进行一些操作并将估计值保存到临时文件中。
SAS没有for
循环。我如何使用do
?
答案 0 :(得分:7)
但sas确实有一个宏循环。 所以基本上你需要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()
这就是主意。 也许您想以不同的方式收集数据集列表。例如,包含它们的宏变量。在这种情况下,您必须使用循环中的%扫描功能来选择数据集。 或者命名中可能存在逻辑,例如,dataset1,dataset2,dataset3 ......,在这种情况下,您可以简单地使用&amp; iter。宏变量。
答案 1 :(得分:7)
另一种选择是创建一个结合了所有数据集的视图,这种方法不会产生任何数据大小问题(虽然我不知道你提到的其他问题是否会成为问题)。您需要一个相关数据集列表,可以从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;
然后只针对视图运行摘要,因此无需遍历每个数据集。我假设您的数据集有一个日期变量,否则您需要添加一些额外的功能(这适用于任何解决方案)。 与其他解决方案相比,看看它的表现会很有趣。
答案 2 :(得分:7)
这就是我在日常编程中解决这个问题的方法,当需要根据数据重复调用宏时。这种方法同样适用于许多数据集或来自一个数据集的许多变量或来自一个数据集的许多不同宏调用 - 无论它们是什么,只需创建一个数据集,其中包含变化的信息并以这种方式调用它。
这种方法将Shorack解决方案的元素与user2337871和Neil's相结合。为什么会有所不同?
dataset_list
数据集可能会有所不同)。call execute
或其他调用方法中)使其更易于阅读。call execute
可能有一些缺点,具体取决于您正在进行的操作(与宏变量计时相关)假设您正在执行PROC方式,然后将其附加到主数据集。虽然这实际上是一种非常缓慢而烦人的方式(与将它们组合在一起并使用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 :(得分:3)
我的回答是宏观。
%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;
答案 4 :(得分:3)
不需要宏,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;