使用SAS中的BY语句对图和表进行分组

时间:2014-08-07 17:39:10

标签: sas sas-ods

我正在使用带有proc boxplot和proc报告的BY语句来为BY变量的每个级别创建一个绘图和一个表。按原样,代码打印所有图,然后打印所有表。我希望它打印绘图,然后打印By变量的每个级别的表(因此输出将在绘图和表之间交替)。有没有办法做到这一点?

这是我目前用于绘图和表格的代码 -

proc boxplot data=study;
plot Lead_Time*Study_ID/ horizontal;
by Project_Name;
format Lead_Time dum.;
run;

proc report data=study nowd;
column ID Title Contact Status Message Audience Priority;
by Project_Name;
run;

谢谢!!

3 个答案:

答案 0 :(得分:1)

不幸的是,我不认为ODS(输出传送系统)可以交错程序的输出。您将需要使用宏来遍历所有变量,并为每个变量调用BOXPLOT和REPORT。

这样的事情:

%macro myreport();
%let byvars = A B C D;
%let n=4;

%do i=1 %to &n;
   %let var = %scan(&byvars,&i);
   proc something data=have(where=(byvar="&var"));
   ...;
   run;

   proc report data=have(where=(byvar="&var"));
   ....
   run;
%end;
%mend;

%myreport();

显然,您需要根据自己的需要进行更改。 Stackoverflow上有很多例子。这是一个:looping over character values in SAS

答案 1 :(得分:1)

原则上可以使用PROC DOCUMENTODS DOCUMENT输出类型。这本身并不容易,但它有可能,并且比宏选项有一些优势,尽管我不确定是否足以推荐它的使用。但是,它值得探索。

首先,在2009年SAS全球论坛期间,Cynthia Zender的优秀教程Have It Your Way: Rearrange and Replay Your Output with ODS DOCUMENT主要指导(包括,巧合地,使用相同的数据集!)。她最初描述了一种这样做的GUI方法,但后来在代码中对它进行了解释,这对于这类事情来说显然是优越的。凯文史密斯在ODS DOCUMENT From Scratch中涵盖了与2012年的SGF相似的基础,尽管辛西娅的论文在这里更适用(因为她涵盖了确切的主题)。

首先,您需要生成所有结果。这里的订单并不重要。 我生成了一个SASHELP.PRDSALE样本,该样本按国家/地区进行了适当排序。

proc sort data=sashelp.prdsale out=prdsale;
by country;
run;

然后,我们生成一些表格;一个proc手段和一个sgplot。请注意标题使用#BYVAL1来确保包含标题 - 否则我们会丢失过程中的有用标签!

title "#BYVAL1 Report";


ods _all_ close;
ods document name=work.mydoc(write);
proc means data=prdsale sum;
 by country;
 class quarter year;
 var predict;
run;

proc sgplot data=prdsale;
 by country;
 vbar quarter/response=predict group=year groupdisplay=cluster;
run;

ods document close;
ods preferences;

现在,我们有一些错误,但可以用于你真正想要的东西。你可以使用Cynthia或Kevin的论文中的技巧来详细研究这个问题。现在我只是为了这个目的而进入你需要的东西。

它现在像这样组织,想象一个文件夹树:

  

\ REPORT \手段\ COUNTRY \

我们需要的是:

  

\ REPORT \ COUNTRY \ MEANS

这很容易做到。这样做的代码如下。显然,对于生产过程,这将更好地自动化;给定输入数据集,生成此代码应该是微不足道的。请注意,BYVAL按值递增,因此CANADA为1和4,德国为2和5,美国为3和6。

proc document name=work.mydoc_new(write);
 make CANADA, GERMANY, USA;   *make the lower level folders;
 run;

 dir ^^;  *Go to the bottom level, think "cd .." in unix/windows;
 dir CANADA;  *go to Canada folder;
 dir;         *Notes to the Listing destination where we are, not that important;
 copy \work.mydoc\Means#1\ByGroup1#1\Summary#1 to ^;  *copy that folder from orig doc to here;
 copy \work.mydoc\SGPlot#1\ByGroup4#1\SGPlot#1 to ^; *^ being current directory, like '.' in unix/windows; 

*您也可以复制\ ByGroup1#1和\ Bygroup4#1而不使用树的最后一级。这样会产生略微不同的结果(表中会包含更多的文字),所以请根据您的期望进行调整。

**德国和美国也是如此。请注意,这是易于自动化的部分!      dir ^^;      德国德里;      DIR;      copy \ work.mydoc \ Means#1 \ ByGroup2#1 \ Summary#1 to ^;      copy \ work.mydoc \ SGPlot#1 \ ByGroup5#1 \ SGPlot#1 to ^;

 dir ^^;
 dir USA;
 dir;
 copy \work.mydoc\Means#1\ByGroup3#1\Summary#1 to ^;
 copy \work.mydoc\SGPlot#1\ByGroup6#1\SGPlot#1 to ^;



run;
quit;  *this is one of those run group procedures, need a quit;

现在,您只需要replay该文档即可以正确的方式解决问题。

proc document name=mydoc_new;
 replay;
 run;
quit;

田田,你有你想要的东西。

答案 2 :(得分:1)

如果您要按值运行一次触发,那很容易。创建一个宏只运行一个实例,然后使用proc sql为每个实例创建一个调用。这是完全动态的,可以很容易地调整,以允许其他选项,如变量,级别等多个。

给出单个值:

*Macro that runs it once;
%macro run_reports(project_name=);
  title "Report for &project_name.";
  proc boxplot data=study;
   plot Lead_Time*Study_ID/ horizontal;
   where Project_Name="&project_name.";
   format Lead_Time dum.;
  run;

  proc report data=study nowd;
   column ID Title Contact Status Message Audience Priority;
   where Project_Name="&project_name.";
  run;
%mend run_Reports;

*SQL pull to create a list of macro calls;
proc sql;
select distinct cats('%run_Reports(project_name=',project_name,')')
  into :runlist separated by ' '
  from study;
quit;

&runlist.;

打开options symbolgen;以查看运行列表的外观,或查看输出窗口(或9.3+中的结果窗口)。在生产中运行此功能时,请将noprint添加到proc sql以避免生成该表。