数据如下:
YEAR MONTH ID1 ID2 FIELD FIELD_DESC
2017 4 123 2222 FFF red1
2017 4 123 2222 FFG red2
2017 4 224 2221 XYZ green1
2017 4 225 1234 TYU blue5
并且所需的输出是
YEAR MONTH ID1 ID2 blue5 green1 red1 red2
2017 4 123 2222 0 0 1 1
2017 4 224 2221 0 1 0 0
2017 4 225 1234 1 0 0 0
在SQL服务器上,我曾经运行以下命令:
select year, month, id1, id2, [field1], [field2] .... [fieldn]
from (select year, month, id1, id2, field, field_desc from source_table) P
Pivot (count(field) for field_desc in ([field1], [field2] .... [fieldn])) Pvt
以上将按年,月,id1,id2给出每个可能描述的字段数。
我试图将其转换为SAS。
一种方法是条件总和
proc sql;
create table aggr_table as
select year, month, id1, id2,
sum(case when field_desc = 'field1' then 1 else 0 end) as field1
...
sum(case when field_desc = 'fieldn' then 1 else 0 end) as fiendn
from source_table
group by year, month, id1, id2;
quit;
我尝试做的第二种方式是
proc sort data = source_table
by year descending month descending id1 descending id2;
run;
data table_aggr (keep year month id1 id2 field1 .... fieldn);
set source_table
retain field1
....
fieldn 0);
if field_desc = 'field1' then do;
field1 = field1 +1;
end;
....
if field_desc = 'fieldn' then do;
fieldn = fieldn + 1;
end;
if last.id2 then
output;
by year month id1 id2;
run;
但第二种方式似乎不起作用
错误:BY变量未在数据集上正确排序 WORK.SOURCE_TABLE
我的问题: 1)到目前为止我的谷歌搜索似乎表明偏好在数据步骤而不是proc sql步骤中进行这种数据操作,是否有特别的优势?
2)我在数据步骤中做错了什么?
3)有没有更好的方法在帖子顶部复制SQL代码?与SQL原始版本相比,我所看到的两种SAS选项看起来都相当笨拙。
谢谢 本
答案 0 :(得分:2)
这就是SAS为PROC提供的功能。
大多数过程中的Off
语句(CLASS
,特别是proc means
)允许您按各种级别进行汇总。例如:
proc tabulate
或者:
proc means data=sashelp.class;
var height weight; *the numeric variables you are calculating with;
class age sex; *the grouping variables;
types () age sex age*sex; *the interactions you want - or use NWAY or WAYS;
run;
根据proc的不同,您可以通过多种方式获取此信息。许多人都有proc tabulate data=sashelp.class;
var height weight; *numeric variables to calculate with;
class age sex; *grouping variables;
tables (all age sex age*sex),(height weight)*n;
run;
个选项或out
语句(例如output
有PROC MEANS
语句来执行此操作)。此外,OUTPUT
可让您以表格形式访问屏幕上打印的所有内容。
ODS OUTPUT
- 或 -
ods output table=want;
proc tabulate data=sashelp.class;
var height weight;
class age sex;
tables (all age sex age*sex),(height weight)*n;
run;
ods output close;
答案 1 :(得分:1)
您可以使用PROC SUMMARY为您计算,然后使用PROC TRANSPOSE将计数转换为变量而不是观察值。如果您只是直接执行此操作,那么对于未显示的组合,您将获得缺失值而不是零。您可以对文件进行后处理,以使用零替换缺少的计数。或者使用下面的方法构建一个CLASSDATA表以提供给PROC SUMMARY,以确保在转置之前包含所有零。
proc sql noprint ;
create table classdata as
select *
from (select distinct year,month,id1,id2 from have) a
, (select distinct field_desc from have) b
;
quit;
proc summary data=have nway classdata=classdata exclusive ;
class year month id1 id2 field_desc ;
output out=counts ;
run;
proc transpose data=counts out=want(drop=_name_);
by year month id1 id2 ;
id field_desc ;
var _freq_;
run;
你可以让PROC SQL直接使用一些棘手的SQL生成完整的排名计数。将数据与id变量值的完整列表组合,并计算两个id变量匹配的次数。
proc sql noprint ;
create table counts as
select year,month,id1,id2
, b.field_desc
, sum(a.field_desc=b.field_desc) as count
from have a
, (select distinct field_desc from have) b
group by year,month,id1,id2,b.field_desc
order by year,month,id1,id2,b.field_desc
;
quit;
生成SQL很简单。如果派生变量的数量很小,那么只需将代码生成为宏变量。 (如果列表很大,则使用数据步骤生成代码,使用call execute()
或将其写入文件并使用%include
运行它。)
proc sql noprint ;
select distinct
catx(' '
,'sum(field_desc ='
,quote(trim(field_desc))
,') as'
,nliteral(field_desc)
)
into :code separated by ','
from have
;
create table want as
select year, month, id1, id2
, &code
from have
group by year, month, id1, id2
;
quit;
如果您想在数据步骤中执行此操作,请查看使用HASH对象来收集数据。然后使用PROC TRANSPOSE或代码生成技术(如上面的SQL中那样)从观察变换到变量。