我想在不手动操作的情况下计算几个变量的增长率。有什么聪明的方法可以做到这一点吗?
例如,请参阅下表sashelp.citiyr
DATE PAN PAN17 PAN18 PANF PANM
1980 227757 172456 138358 116869 110888
1981 230138 175017 140618 118074 112064
1982 232520 177346 142740 119275 113245
1983 234799 179480 144591 120414 114385
1984 237001 181514 146257 121507 115494
1985 239279 183583 147759 122631 116648
1986 241625 185766 149149 123795 117830
1987 243942 187988 150542 124945 118997
1988 246307 189867 152113 126118 120189
1989 248762 191570 153695 127317 121445
我可以按如下方式创建变量的增长率(例如第一列PAN
(,但我想要一种方法来计算所有变量(或我想要的变量,想象一个有几十个变量的情况(。
data test;
set sashelp.citiyr;
by date;
Pan_growth = PAN / lag(PAN);
run;
知道如何让它更聪明吗?
转置数据集并使用 BY 组处理。
*transpose to a long format;
proc transpose data=have out=long (rename=col1=Value);
by date;
var pan--panm;
run;
*sort for each variable to be consistent;
proc sort data=long;
by _name_ date;
run;
*calculate lag;
data want;
set long;
by _name_;
prev_val = lag(value);
if not(first._name_) then growth = value/prev_value - 1;
run;
您可以使用宏。此外,为了避免收到警告,您需要一些条件逻辑来防止第一行的除法
data test;
set sashelp.citiyr;
by date;
%macro growth(var);
before=lag(&var);
if _N_>1 then &var._growth = &var. / before;
drop before;
%mend;
%growth(PAN);
%growth(PAN17);
%growth(PAN18);
%growth(PANF);
%growth(PANM);
run;
使用数组。
data test;
set sashelp.citiyr;
array vars[*] pan pan17 pan18 panf panm;
array growth[*] pan_growth pan17_growth pan18_growth panf_growth panm_growth;
do i = 1 to dim(vars);
growth[i] = vars[i]/lag(vars[i]);
end;
run;
如果变量都以某个前缀开头、以序列号结尾或始终以完全相同的顺序结束,则可以使用变量列表快捷方式节省更多时间。
如果您遇到更复杂的情况,即有数百个顺序不正确或没有简单模式的变量,则可以生成所需的名称并使用 SQL 和dictionary.columns
将它们保存到宏列表中。只需确保从查询中排除任何不相关的变量即可。
proc sql noprint;
select name
, cats(name, '_growth')
into :vars separated by ' '
, :growth_vars separated by ' '
from dictionary.columns
where libname = 'SASHELP'
AND memname = 'CITIYR'
AND upcase(name) NE 'DATE'
;
quit;
data test2;
set sashelp.citiyr;
array vars[*] &vars.;
array growth[*] &growth_vars.;
do i = 1 to dim(vars);
growth[i] = vars[i]/lag(vars[i]);
end;
run;