我有一系列标题为Income_2015
,Interest 2015
,Dividends 2015
,Income_2018
,Interest 2018
,Dividends 2018
等的列,并希望创建每年的总列数。
是否有一种方法可以在SAS中执行此操作而不必单独列出总和中的所有列
我目前使用以下内容按类型获取总计:
data keep;
set from;
income_total = sum(of Income_:);
run;
除非使用以下方法,否则找不到按年总计的方法:
year_2015_total = sum(Income_2015, Interest_2015, Dividends_2015)
...
year_2018_total = sum(Income_2018, Interest_2018, Dividends_2018)
我很高兴可以完成上述操作,但这只是我需要包括的几列示例。实际的列表要长得多
答案 0 :(得分:0)
没有一种通过后缀定义变量列表的简单/自动方法。也就是说,没有任何直接等效于sum (of :2018)
的东西。
也就是说,您可以选择。一种是使用数组。它们使您可以按数组名称引用变量列表。
另一种是使用宏语言。这样,您就可以构建一个宏变量,该宏变量包含具有特定后缀的所有变量名的列表。
但是我认为最好的解决方案是重组数据。
如果您的数据现在看起来像:
Person Income_2015 Interest_2015 Income_2016 Interest_2016
1 100,000 1,000 200,000 2,000
2 500,000 5,000 600,000 6,000
将其移至:
Person Year Income Interest
1 2015 100,000 1,000
1 2016 200,000 2,000
2 2015 500,000 5,000
2 2016 600,000 6,000
这种垂直结构使处理数据变得更加容易,并且您可以轻松地跨年(列)或收入来源(行)进行汇总。关键是年份实际上是一个数据值。因此,垂直(“规范化”)结构通过将Year作为值存储在变量中而不是将Year作为变量名称的一部分来存储,而使您受益。
答案 1 :(得分:0)
您可以尝试使用宏变量,例如:
proc sql;
select name into:list_2015 separated by ',' from dictionary.columns where libname='YOURLIB' and memname='YOURDATA' and name contains '2015';
quit;
data want;
set have;
sum_2015=sum(of &list_2015);
run;
答案 2 :(得分:0)
不幸的是,您的数据设计已将数据元素存储为元数据的一部分(变量名的一部分),并且您获得的数据集越来越大。
分类形式适用于汇总汇总,并使用诸如TABULATE
或REPORT
之类的报告过程来生成数据的“广泛”视图。
id topic year amount
a income 2015
a interest 2015
a dividends 2015
a losses 2015
b income 2015
b interest 2015
b dividends 2015
… no losses row for id=b corresponds to 'missing' value in wide form
c income 2015
c interest 2015
… c had no dividends, no losses, no fubars
保持结构不变(有时候,就像跨60年的一千万个帐户的大型机数据一样),您需要对数据集进行预处理,以识别包含年份和值等年份的列后续步骤代码中的信息,其中包含代码生成(即宏),该代码生成涵盖了列名中的年份。例如:
%macro make_data(data=);
%local year category index varname;
data &data;
do accountid = 1 to 20;
%do index = 65 %to 90;
%do year=1995 %to 2019;
%let varname = %sysfunc(byte(&index))_&year;
amount+1;
&varname = amount;
%end;
%end;
output;
end;
drop amount;
run;
%mend;
%macro generate_year_total_code(data=);
proc contents noprint data=&data out=havemeta(keep=name);
run;
data havemeta2;
set havemeta;
if prxmatch ("/[^0-9]\d{4}/", trim(name));
year = input(substr(name,length(name)-3), 4.);
run;
proc sort data=havemeta2;
by year;
run;
data _null_;
length varlist $32000;
do until (last.year);
set havemeta2;
by year;
varlist = catx(',', varlist, name);
end;
call symputx('year_count', _n_);
call symput ( cats('total_statement_', _n_)
, cats('total_',year,'=sum(',varlist,')'));
run;
%mend;
%macro totals(data=);
%generate_year_total_code(data=&data);
%local index;
data &data;
set &data;
%do index = 1 %to &year_count;
&&total_statement_&index;
%end;
run;
%mend;
%make_data(data=have);
options mprint;
%totals(data=have);
另一种方法是将数据转换为分类形式,以便提取年份值以进行适当汇总或用于分类报告中。例如:
proc transpose data=have out=haveTall;
by accountid;
run;
data haveTall;
set haveTall;
if prxmatch ("/_\d{4}$/", trim(_name_)); * data value in col1 is from a year suffixed variable name;
year = input(substr(_name_,length(_name_)-3), 4.);
category = substr(_name_,1, length(_name_)-5);
amount = col1;
drop _name_ col1;
run;
proc tabulate data=haveTall;
class accountid category year;
var amount;
table
accountid * category
,
year=''*amount=''*sum=''
/
nocellmerge
;
run;
第三种更复杂但简洁的方式。使用哈希对象动态计算总计,输出总计并合并回原始数据。与方法#1相比,这需要更多的CPU,因为PDV变量名称是在每一行中求值的。
data _null_;
if 0 then set have(keep=accountid);
length year amount 8;
declare hash totals(ordered:'a');
totals.defineKey('accountid', 'year');
totals.defineData('accountid', 'year', 'total');
totals.defineDone();
call missing (year, amount, accountid);
do until (end);
set have end=end;
array numbers _numeric_;
do over numbers;
length name $32;
name = vname(numbers);
if prxmatch ("/_\d{4}$/", trim(name)) then do;
year = input(substr(name,length(name)-3), 4.);
if totals.find() = 0
then total + numbers;
else total = numbers;
totals.replace();
end;
end;
end;
totals.output(dataset:'totals');
stop;
run;
proc transpose data=totals prefix=total_ out=totals_across_year(drop=_name_);
by accountid;
var total;
id year;
run;