加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

SAS编程技巧--频数统计

(2012-12-27 18:25:32)
标签:

杂谈

分类: SAS_Quick_Tips

这篇算是《SAS编程技巧--数据汇总》的姐妹篇,在数据汇总那篇文章中我们用 SUMMARY 过程计算了所有数值型变量的频数以及各种统计量,今天我们看看如何用 SAS 对分类变量进行频数分析。这篇文章纯粹是编程方面的讨论,比较枯燥,但是编程中遇到的问题及其解决办法个人认为很是有趣,而且我建议大家下去试试有没有更好的解决办法。

 

假设我们现在需要对数据集中所有分类变量进行频数分析,并将结果保存至 SAS 数据集,期望的结果如下:

varname level Frequency Percent CumFrequency CumPercent
sex M 10 52.63 10 52.63
sex F 9 47.37 19 100.00
age 12 5 26.32 5 26.32
age 14 4 21.05 9 47.37
age 15 4 21.05 13 68.42
age 13 3 15.79 16 84.21
age 11 2 10.53 18 94.74
age 16 1 5.26 19 100.00

 

我们先从最简单的情况入手,即只有字符型的变量才是分类变量,不考虑数值型变量,也不考虑字符型客户号码等极端情况。看到这个题目,大家基本上都会选择 FREQ 过程步的 TABLES 语句加 OUT 选项,如下所示。

 

proc freq data=sashelp.class order=freq noprint;
   tables (_character_)/missing out=freq_one_var;
run;quit;

 

输出结果(表 1):

Sex COUNT PERCENT
M 10 52.6316
F 9 47.3684

 

从表 1 我们可以看到只有最后一个变量的结果保存到数据集中,其他变量的结果没有保存。为了解决这个问题,我们使用 ODS OUTPUT 语句。

 

ods output onewayfreqs=onewayfreqs;
proc freq data=sashelp.class order=freq;
   tables (_character_)/missing;
run;quit;

 

输出结果(表 2):

Table F_Name Name Frequency Percent CumFrequency CumPercent F_Sex Sex
Table Name Alfred Alfred 1 5.26 1 5.26
Table Name Alice Alice 1 5.26 2 10.53
Table Name Barbara Barbara 1 5.26 3 15.79
Table Name Carol Carol 1 5.26 4 21.05
Table Name Henry Henry 1 5.26 5 26.32
Table Name James James 1 5.26 6 31.58
Table Name Jane Jane 1 5.26 7 36.84
Table Name Janet Janet 1 5.26 8 42.11
Table Name Jeffrey Jeffrey 1 5.26 9 47.37
Table Name John John 1 5.26 10 52.63
Table Name Joyce Joyce 1 5.26 11 57.89
Table Name Judy Judy 1 5.26 12 63.16
Table Name Louise Louise 1 5.26 13 68.42
Table Name Mary Mary 1 5.26 14 73.68
Table Name Philip Philip 1 5.26 15 78.95
Table Name Robert Robert 1 5.26 16 84.21
Table Name Ronald Ronald 1 5.26 17 89.47
Table Name Thomas Thomas 1 5.26 18 94.74
Table Name William William 1 5.26 19 100.00
Table Sex 10 52.63 10 52.63 M M
Table Sex 9 47.37 19 100.00 F F

 

表 2 中包含了所有变量的频数统计结果,但是这并不是我们想要的表结构,我们希望对表 2 进一步处理,生成最后的结果。


%let data=sashelp.class;
%let vars =name sex;

ods output onewayfreqs=onewayfreqs;
proc freq data=&data order=freq;
   tables (&vars)/missing;
run;quit;

 

data freq_out;
   length varname $ 32;
   length level $ 100;
   set onewayfreqs(keep=&vars frequency percent cumfrequency cumpercent);
   array varlist{*} $100 &vars;
   do i=1 to dim(varlist);
      if varlist(i) ne '' then do;
         varname = scan("&vars", i);
         level=strip(varlist(i));
         return;
      end;
   end;
   keep varname level frequency percent cumfrequency cumpercent;
run;

 

输出结果(表 3): 

varname level Frequency Percent CumFrequency CumPercent
name Alfred 1 5.26 1 5.26
name Alice 1 5.26 2 10.53
name Barbara 1 5.26 3 15.79
name Carol 1 5.26 4 21.05
name Henry 1 5.26 5 26.32
name James 1 5.26 6 31.58
name Jane 1 5.26 7 36.84
name Janet 1 5.26 8 42.11
name Jeffrey 1 5.26 9 47.37
name John 1 5.26 10 52.63
name Joyce 1 5.26 11 57.89
name Judy 1 5.26 12 63.16
name Louise 1 5.26 13 68.42
name Mary 1 5.26 14 73.68
name Philip 1 5.26 15 78.95
name Robert 1 5.26 16 84.21
name Ronald 1 5.26 17 89.47
name Thomas 1 5.26 18 94.74
name William 1 5.26 19 100.00
sex M 10 52.63 10 52.63
sex F 9 47.37 19 100.00

 

有时候我们不能简单地根据变量的类型来决定变量的测量水平,因为有些数值型变量也可能是分类变量,例如:客户类型既可以用字符表示,也可以用数值表示。上面的代码只能处理字符型分类变量,因为我们使用了数组 array varlist{*} $100 &vars;,而数组要求所有元素的类型与其类型都是一致的。有人可能会说表 2 中所有 F_ 开头的变量都是字符型的,恰好没有这个限制,但是使用 F_ 开头的变量会令你的代码变得相当复杂,因为有很多情况需要考虑,包括 SAS 软件本身的限制(变量名长度不能多于 32 个字符)。对于一些极端的情况,比如恰巧有两个变量,分别取名为:longagenaaaaaaaaaaaaaaaaaaaaameh 和longagenaaaaaaaaaaaaaaaaaaaaamew,在生成的频数结果表中只有 longagenaaaaaaaaaaaaaaaaaaaaameh 对应的 F_ 变量,没有 longagenaaaaaaaaaaaaaaaaaaaaamew 对应的 F_ 变量。

 

 

对于数值型、字符型混合的情况,我们需要重新编码,克服上述所有问题。其中,用到了 MISSING 选项,这个我在《SAS编程技巧--巧用MISSING选项》里面有介绍。


%let data=sashelp.class;
%let vars =sex age;

 

ods output onewayfreqs=onewayfreqs;
proc freq data=&data order=freq;
   tables (&vars)/missing;
run;quit;

 

options missing='';
data freq_out;
   length varname $ 32;
   length level $ 100;
   set onewayfreqs(keep=table &vars frequency percent cumfrequency cumpercent);
   by table notsorted;
   retain tableno 0;
   if first.table then tableno + 1;
   varname = scan("&vars", tableno);
   level=cats(%sysfunc(tranwrd(&vars, %str( ), %str(,))));
   if missing(level) then level='_missing_';
   keep varname level frequency percent cumfrequency cumpercent;
run;
options missing=.;

 

输出结果(表 4):

varname level Frequency Percent CumFrequency CumPercent
sex M 10 52.63 10 52.63
sex F 9 47.37 19 100.00
age 12 5 26.32 5 26.32
age 14 4 21.05 9 47.37
age 15 4 21.05 13 68.42
age 13 3 15.79 16 84.21
age 11 2 10.53 18 94.74
age 16 1 5.26 19 100.00

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有