我有 60 个 sas 数据集,其中包含有关消费者个人特征的数据,例如 id, gender, age, amountSpent, ....
每个数据集仅显示一个时间段的数据(数据 1 是 1 月,数据 2 是 2 月......)。由于大小和其他一些问题,我无法合并它们。
如何编写多个循环来遍历每个数据集,进行一些操作并将估计值保存到临时文件中。
SAS 没有for
循环。我该如何使用do
?
这就是我在日常编程中解决这个问题的方法,当需要根据数据重复调用宏时。这种方法同样适用于许多数据集或来自一个数据集的许多变量或来自一个数据集的许多不同的宏调用 - 无论是什么,只需创建一个包含变化信息的数据集并以这种方式调用它。
这种方法将 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 或许多不同的选项来调用它。您还可以使用带有数据集名称的自制数据集(如果感兴趣的变量因数据集而异,甚至可以将变量作为另一列和宏参数)。
另一种选择是创建一个组合所有数据集的视图,使用这种方法不会遇到任何数据大小问题(尽管我不知道您提到的其他问题是否会成为问题)。您需要相关数据集的列表,可以从 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;
然后只需针对视图运行摘要,因此无需遍历每个数据集。我假设您的数据集有一个日期变量,否则您需要添加一些额外的功能(这适用于任何解决方案)。与此处的其他解决方案相比,看看它的表现会很有趣。
但是 sas 确实有一个 do while 宏循环。所以基本上你需要三样东西: 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。宏变量。
不需要宏,CALL EXECUTE 将通过简单地在 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;
我的首选答案是宏。
%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;