我有一个数据集,每个国家/地区有一行,100列(10个变量,每个数据年数为10年)。
对于每个变量,我试图为每个国家(可能不是连续的)的变量创建一个新的数据集,其中包含最近三年的数据年份。
这是我到目前为止所做的,但我知道它的错误是因为嵌套循环,并且recent1 recent2 recent3
具有相同的值但是我还没弄明白如何创建recent1 recent2 recent3
没有两个循环。
%macro test();
data Maternal_care_recent;
set wb;
keep country MATERNAL_CARE_2004 -- MATERNAL_CARE_2013 recent_1 recent_2 recent_3;
%let rc = 1;
%do i = 2013 %to 2004 %by -1;
%do rc = 1 %to 3 %by 1;
%if MATERNAL_CARE_&i. ne . %then %do;
recent_&rc. = MATERNAL_CARE_&i.;
%end;
%end;
%end; run; %mend; %test();
答案 0 :(得分:3)
您不需要使用宏来执行此操作 - 只需要一些数组:
data Maternal_care_recent;
set wb;
keep country MATERNAL_CARE_2004-MATERNAL_CARE_2013 recent_1 recent_2 recent_3;
array mc {*} MATERNAL_CARE_2004-MATERNAL_CARE_2013;
array recent {*} recent1-recent3;
do i = 2013 to 2004 by -1;
do rc = 1 to 3 by 1;
if mc[i] ne . then do;
recent[rc] = mc[i];
end;
end;
run;
答案 1 :(得分:0)
也许我没有收到您的请求,但根据您的说明: "对于每个变量,我试图为每个国家(可能不是连续的)变量的三个最近数据年创建一个新的数据集。我用dt1和dt2以及2个位置创建了这个样本数据集。
输出将是2个数据集(通常是以DT开头的变量的数量),名为DS1和DS2,每个国家有3个观测值,第一个用于第一个变量,第二个用于第二个变量。
这是样本数据集:
data sample_ds;
length city $10 dt1 dt2 8.;
infile datalines dlm=',';
input city $ dt1 dt2;
datalines;
MS,5,0
MS,3,9
MS,3,9
MS,2,0
MS,1,8
MS,1,7
CA,6,1
CA,6,.
CA,6,.
CA,2,8
CA,1,5
CA,0,4
;
这是示例宏:
%macro help(ds=);
data vars(keep=dt:); set &ds; if _n_ not >0; run;
%let op = %sysfunc(open(vars));
%let nvrs = %sysfunc(attrn(&op,nvars));
%let cl = %sysfunc(close(&op));
%do idx=1 %to &nvrs.;
proc sort data=&ds(keep=city dt&idx.) out=ds&idx.(where=(dt&idx. ne .)) nodupkey; by city DESCENDING dt&idx.; run;
data ds&idx.; set ds&idx.;
retain cnt;
by city DESCENDING dt&idx.;
if first.city then cnt=0; else cnt=cnt+1;
run;
data ds&idx.(drop=cnt); set ds&idx.(where=(cnt<3)); rename dt&idx.=act&idx.; run;
%end;
%mend;
您将使用以下命令运行此宏:
%help(ds=sample_ds);
在宏的第一个语句中,我选择了我想要迭代的变量:
data vars(keep=dt:); set &ds; if _n_ not >0; run;
如果你想让你的代码工作,或者只是将你的变量重命名为DT1 DT2 ......
让我知道你是否正确。
答案 2 :(得分:0)
编写宏代码时,请始终牢记在何时需要执行的操作。 SAS逐步处理代码。
当您编写%if MATERNAL_CARE_&i. ne . %then %do
时,这是在编译之前解释的宏代码。
那时MATERNAL_CARE_&i.
不是变量,而是包含宏变量的文本字符串。
第一次运行%do i = 2013 %to 2004 by -1
时,它会以MATERNAL_CARE_2013
填充,第二次填充为MATERNAL_CARE_2012.
,等等。
然后解释宏%if
语句,并且由于文本字符串MATERNAL_CARE_1不等于点,因此将其评估为FALSE
并且recent_&rc. = MATERNAL_CARE_&i.
未包含在要传递给编译器的代码中。
如果您使用 option mprint
;
决议;
options mprint;
%macro test();
data Maternal_care_recent;
set wb;
keep country MATERNAL_CARE_: recent_:;
** The : acts as a wild card here **;
%do i = 2013 %to 2004 %by -1;
if MATERNAL_CARE_&i. ne . then do;
%do rc = 1 %to 3 %by 1;
recent_&rc. = MATERNAL_CARE_&i.;
%end;
end;
%end;
run;
%mend;
%test();
现在,在编译if MATERNAL_CARE_&i. ne . then do
之前,只有&i.
被评估,if MATERNAL_CARE_2013 ne . then do
被传递给编译器。
如果SAS变量MATERNAL_CARE_1
缺少值,编译器会将此视为测试,这正是您想要的;
<强>注:强>
我把if语句移到了``之上并不重要。它的效率更高,因为这种情况的评估频率较低。
但是,您必须使用%if
以及%do
和%end
if
关闭do
和end
s ;
<强>注:强>
您不需要%let rc = 1
,因为%do rc = 1 to 3
已初始化&amp; rc .;
为了完整性,SAS逐步编译:
下一个 PROC 或数据步骤及其宏代码仅在执行preveous时才考虑。
这就是为什么你可以从数据步骤或sql select into
中编写宏变量来影响你在下一步中编译的代码,
有些你不能用例如C ++预编译;
答案 3 :(得分:0)
谢谢大家。找到了几个解决方案的混合解决方案。
data sample_ds;
infile datalines dlm=',';
input country $ maternal_2004 maternal_2005
maternal_2006 maternal_2007 maternal_2008 maternal_2009 maternal_2010 maternal_2011 maternal_2012 maternal_2013;
datalines;
MS,5,0,5,0,5,.,5,.,5,.
MW,3,9,5,0,5,0,5,.,5,0
WE,3,9,5,0,5,.,.,.,.,0
HU,2,0,5,.,5,.,5,0,5,0
MI,1,8,5,0,5,0,5,.,5,0
HJ,1,7,5,0,5,0,.,0,.,0
CJ,6,1,5,0,5,0,5,0,5,0
CN,6,1,.,5,0,5,0,5,0,5
CE,6,5,0,5,0,.,0,5,.,8
CT,2,5,0,5,0,5,0,5,0,9
CW,1,5,0,5,0,5,.,.,0,7
CH,0,5,0,5,0,.,0,.,0,5
;
%macro test(var);
data &var._recent;
set sample_ds;
keep country &var._1 &var._2 &var._3;
array mc {*} &var._2004-&var._2013;
array recent {*} &var._1-&var._25;
count=1;
do i = 10 to 1 by -1;
if mc[i] ne . then do;
recent[count] = mc[i];
count=count+1;
end;
end;
run;
%mend;