数学建模社区-数学中国

标题: sas提高处理大数据效率的一些实用技巧 [打印本页]

作者: wangzheng3056    时间: 2014-4-17 15:38
标题: sas提高处理大数据效率的一些实用技巧
摘要: 测试代码的时候,可以从大数据集中抽取一部分数据来进行测试,而不比直接在大文件上全部进行测试。抽取数据这个有好多种方法常用的如使用obs=option选项,proc surveyselect进行分层抽样,利用种子产生随机数来抽取等 ...: j3 |* ?0 s+ n( s

5 u3 p0 Q  e, k! T
1 W$ c/ B0 K! t) K/ {3 I, R7 \3 K! h* t9 @- A0 H$ @; K& C* {
以下是自己总结的一些方法,欢迎拍砖,添砖加瓦。6 U0 x. [3 K+ o4 `
1.测试代码的时候,可以从大数据集中抽取一部分数据来进行测试,而不比直接在大文件上全部进行测试。抽取数据这个有好多种方法常用的如使用obs=option选项,proc surveyselect进行分层抽样,利用种子产生随机数来抽取等等,反正怎么方便怎么取。如
proc means data=test(obs=1000);
run;
或者
options obs=1000;   
proc means data=test;   
run;
options obs=max;
2.每个数据集最好只保留自己想要的变量,变量太多是会影响效率的,所以无关变量可以drop掉,或者keep想要的变量。

% l9 V$ ]3 m5 {# Q6 w1 n7 w
3.在对符合已知变量条件的记录进行处理时,果断先进行筛选,然后在进行处理。同时在 Data步建立新数据集,在进行的条件筛选中,where的效率比if高,因为where在读入的时候就已经进行判断,而if则是等到全部读完的时候才进 行判断。如需对class数据集中的男生建立一个新变量weight_new,以下这种写法是不可取的。
/ L1 u( v' G) H, D! {. Z/ K7 c
data test;
            set sashelp.class;
            weight_new=sum(height,-101);
            if  sex=”男”;
     run;
可以这么写
data test;
            set sashelp.class(Where =(sex=”男”));
            weight_new=sum(height,-101);
     run;
4.一些能省略的data步,如先经过data步进行简单的条件筛选,然后进行proc步的一些操作,诸如此类的data步,尽量省略吧。
data test;
                set  sashelp.class;
                where  sex=”男”;
     run;
     proc means data=test;
                var  weight height;
     run;
完全可以这么写
proc means data=test(where=(sex=”男”));
                var  weight  height;
     run;
5.需要修改数据集变量的label和format格式时,还是通过proc datasets过程进行修改效率比较快,它不需要记录进入pdv,比起data步更有效率。
data test;           
     set sashelp.class;           
      label weight="体重(斤)";            
      format weight best6.2;   
run;      
2 Q" Q: f, C' \% `. M" S0 u3 _$ u
proc datasets library=sashelp;            
     modify class;            
     label weight="体重(斤)";           
     format weight best6.2;   
run;   
quit;
6.纵向合并数据集时,如果生成的目标表就是来源表之一,那么proc append会比data步更有效率。
data test1;
       do  i=1 to 10000000;
              x=1;y=1;z=1;
       output;
       end;
run;

% |$ ^& v. k1 V, n( e
data test2;
       do  i=1 to 10000000;
            x=1;y=1;z=1;
            output;
    end;
run;
   data test1;
          set test1 test2;
    run;
- `# [# ^4 `+ s2 y  t8 B. e
/*proc append*/
    data test1;
          set test1;
          stop;
    run;
    proc append base=test1 data=test2;
    run;
/*proc datasets中的append*/
    data test1;
          set test1;
          stop;
    run;
proc datasets library=work;
modify test;
append base=test1data=test2;
run;
quit;
proc append和proc datasets中的append过程效率是一样的。

9 C/ R* e7 K4 h" @
7.对于大数据集,一般都会讲数据集压缩,以节省存储空间,sas里可以通过options compress=yes;来进行压缩。

; k% A1 a  D0 ^/ m) M
8.如果我们想要查看一个变量顶部5%的记录,可以通过proc rank一步实现,而不需先通过univariate过程先将p95分位数求出,然后赋值给宏变量,最后再回到数据集中筛选。
data test;
        do   i=1 to 200;
            output;
        end;
    run;
    proc rank data=test groups=100 out=want(where=(i_pct>=95));
          var    i;
          ranks   i_pct;
    run;
9.在编写一些proc步时,对于分组变量最好是用class而不用by,因为用by是得对分组变量进行排序的。
- ?+ [- W8 V4 H) {' Z0 ]
10.视图的应用。视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是, 视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。所以视图能够节省大量的空间,同时 因为它不是以存储的形式存在,因此在一定程序上能够提高运行效率。如对生成的数据集进行means过程
data test1/view=test1;
        do i=1 to 30000000;
              x=1;y=1;z=1;output;      
        end;   
run;     
proc means data=test1;         
        var   i;   
run;

3 g2 B+ `) M% P: e& ^
data test2;
       do i=1 to 30000000;
            x=1;y=1;z=1;
       output;
       end;   
run;     
proc means data=test2;        
       var   i;   
run;
对比之下,我们可以看到视图比起数据集将近节省了10秒。但是引用视图的时候要注意,视图的名字能够覆盖视图的名字,但是它不能覆盖数据集的名字,因此建 立视图的时候,不能存在跟视图一样名字的数据集,否则会报错。同时,如果视图的名字存在,再要建立同样名字的数据集也是会报错。

: H  r% J, K' {3 M) m. y- l
3 u+ V( `( b2 X+ N/ |
11.format格式数据集的引用。比如说在信用卡交易数据集,每天的交易量都是很大的,同时包括境内境外交易,这时就存在币种转换问题。一张交易量很 大的表,和一张币种汇率表,这时如果通过币种去连接两个数据集,首先得先对这两个数据集按币种排序,然后merge进行计算,当然有人想到直接用sql连 接,不过这样消耗时间也都是非常大的。这时候就可以先将汇率表做成format的数据集形式,到时就可以直接使用了。如
data rate;
input currency $ rate date yymmdd10.;
format date yymmdd10.;
cards;
USD 6.13 2013/6/11
EUR 8.14 2013/6/11
GBP 9.56 2013/6/11
JPY 5.80 2013/6/11
HKD 0.78 2013/6/11
;
run;
1 @& v5 ^1 f3 ?1 p2 C) {7 {
data trans;
input id $ currency $ money;
cards;
001 USD 200
002 GBP 100
003 USD 120
004 HKD 1000
005 EUR 300
;
run;

6 [, x  O  ^% a. o9 _3 e& A) }
proc sort data=rate nodupkey;
        by currency;
run;
6 _7 k) u  y3 P3 H) X9 R
data rate_format;
        set rate end=last;
        retain fmtname 'rate_fmt' type 'c';
        rename currency=start rate=label;
        drop date;
run;

  W- o  y. X& d% M8 B4 q) j% e
/*options fmtsearch=(sashelp);*/
4 ^1 h9 T7 z+ c
proc format library=work cntlin=rate_format;
run;

; I3 S: x& R; |. n0 C6 \# v
data trans_amt;
        set trans;
        rate=put(currency,$rate_fmt.);
        money_to_rmb=money*rate;
run;
注意format数据集的地址,如果非work逻辑库下,则需要加上这么一句话options fmtsearch=(逻辑库名称);
* `1 a6 z; [" X9 W- _+ \% S( i
12.将数据集载入内存。该方法减少数据集内存分配和释放的次数,降低I/O处理量,提高SAS程序执行效率,但是相当消耗内存,需要确认系统有足够多的内存资源,同时在使用完后,要记得释放。具体形式如下
sasfile test2 load;/*将数据集test2载入内存*/
data test;
set test2;
run;
proc means data=test2;
run;
sasfile test2 close;/*将test2数据集从内存中释放*/
13.hash的应用。在data步中使用hash对象,不但可以快速有效地检索和读取数据,还可以实现数据集 merge的功能,从而减少排序时间,提高了数据处理的能力,相对于merge,hash的效率更高,但是同时也很消耗内存,因此一般都是把小表放进 hash中。如用前面汇率进行币种的连接
data test;
        if _n_=0 then set rate;
        if _n_=1 then do;
                declare hash  share(dataset:'work.rate');
                        share.definekey('currency');
                        share.definedata(all:'yes');
                        share.definedone();
        call missing (of _all_);
        end;
        set Trans;
        if share.find()=0;
run;

. a+ t. Y# n; _# K# M+ F4 L

; G" x% a3 `! d) N" [
1 A! C% Y5 v5 \7 g
作者: 张泽华    时间: 2014-4-17 17:52
好好好,楼主辛苦了!
作者: 谭宝    时间: 2014-4-25 14:20
楼组辛苦了




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5