在 SAS 中旋转 table
Pivot table in SAS
数据如下:
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;
但是第二种方式好像不行
ERROR: BY variables are not properly sorted on data set
WORK.SOURCE_TABLE
我的问题:
1) 到目前为止,我的谷歌搜索似乎表明我更喜欢在数据步骤而不是 proc sql 步骤中进行这种数据操作,这有什么特别的优势吗?
2) 我在数据步骤中做错了什么?
3) 是否有更好的方法来复制 post 顶部的 SQL 代码?与 SQL 原始版本相比,我正在查看的两个 SAS 选项看起来都相当笨拙。
谢谢
本
这就是 SAS 提供 PROC 的目的。
大多数过程中的 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 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
让您基本上可以访问以 table 形式打印在屏幕上的所有内容。
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;
--或--
proc tabulate data=sashelp.class out=want;
var height weight;
class age sex;
tables (all age sex age*sex),(height weight)*n;
run;
您可以使用 PROC SUMMARY 为您计数,然后使用 PROC TRANSPOSE 将计数转化为变量而不是观察值。如果您直接这样做,那么对于未出现的组合,您将得到缺失值而不是零。您可以 post 处理文件以用零替换丢失的计数。或者使用下面的方法构建一个 CLASSDATA table 以提供给 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 中的那样)将观察值转换为变量。
数据如下:
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;
但是第二种方式好像不行
ERROR: BY variables are not properly sorted on data set WORK.SOURCE_TABLE
我的问题: 1) 到目前为止,我的谷歌搜索似乎表明我更喜欢在数据步骤而不是 proc sql 步骤中进行这种数据操作,这有什么特别的优势吗?
2) 我在数据步骤中做错了什么?
3) 是否有更好的方法来复制 post 顶部的 SQL 代码?与 SQL 原始版本相比,我正在查看的两个 SAS 选项看起来都相当笨拙。
谢谢 本
这就是 SAS 提供 PROC 的目的。
大多数过程中的 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 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
让您基本上可以访问以 table 形式打印在屏幕上的所有内容。
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;
--或--
proc tabulate data=sashelp.class out=want;
var height weight;
class age sex;
tables (all age sex age*sex),(height weight)*n;
run;
您可以使用 PROC SUMMARY 为您计数,然后使用 PROC TRANSPOSE 将计数转化为变量而不是观察值。如果您直接这样做,那么对于未出现的组合,您将得到缺失值而不是零。您可以 post 处理文件以用零替换丢失的计数。或者使用下面的方法构建一个 CLASSDATA table 以提供给 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 中的那样)将观察值转换为变量。