SAS能自己编写函数么?
偶然情况下载help里面看到的一个过程步proc fcmp;就到网上查了些资料,原来SAS也可以编写自己的function并调用,可以使复杂的函数瞬间变简单有木有!!!
proc fcmp outlib=function.funcsol.conversion
function change(lb);
kg=lb/2.2;
return (kg);
endsub;
run;
复制代码
恭喜大家,这样已经定义了一个属于你自己的函数了,名字叫做change,储存在function.funcsol.conversion 里面;需要注意的是储存的文件夹,也就是function.funcsol.conversion 一定是由三个目录组成的,WHY?
大家可以定义了这个函数之后自己去打开文件看一下,首先是主文件夹function(相当于work), 然后是funcsol(相当于数据集),
而conversion就相当于数据集里的索引了,我个人觉得SAS储存函数还是与储存数据是一样的,把编译了的函数储存在数据集里相当于,个人理解,希望大神指正,这样想便于理解嘛;
语法方面并不是很复杂,我就随便说一下;
相当于do循环有end;
function 有 endsub;如果大家会VB的话,对sub肯定不陌生吧?打VBA天天打有木有~~~
剩下的就简单了,定义一个变量,计算,然后返回计算出来的值,函数结束;
接下来就和format一样,(或者是matlab里面的path),你要告诉SAS到哪里去找你定义的函数;
options cmplib=(function.funcsol);
复制代码
OK, 这样子SAS应该已经知道到哪里去找了;
接下来试一下效果:
data a;
set sashelp.class(keep=name age weight);
kilos=change(weight);
run;
复制代码
这样我们就成功的调用了自己定义的函数;
最简单的例子就是这样了,接下来是进阶教程:
proc fcmp outlib=function.funcsol.conversions;
function lb2kgc(lb) $;
length kg $10;
kg = catt(put((lb/2.2),6.2),'kg');
return (kg);
endsub;
run;
复制代码
这个是什么?和前面不同的只有一点,就是return的不是一个数值型变量而是一个字符型变量;
SO,和定义变量一样,加一个 $ 就好;
其他的语法都是一样的,只是一个catt的连接函数而已;
options cmplib=(function.funcsol);
data b;
set sashelp.class(keep=name age weight);
kilos=change(weight);
kg_c=lb2kgc(weight);
run;
复制代码
一样的,试一下;
proc fcmp outlib=function.funcsol.conversions;
function bmi(lb,ht);
return((lb*703)/(ht*ht));
endsub;
run;
options cmplib=(function.funcsol);
data bmi;
set sashelp.class(keep=name age weight height);
bmi=bmi(weight,height);
run;
复制代码
OK,两个自变量,right?
接下来两个例子我觉得写得爆赞,可以一窥函数定义的妙处所在;
proc fcmp outlib=function.funcsol.conversions;
subroutine biomassindex(w,h,b);
outargs b;
b= ((w*703)/(h*h));
endsub;
run;
options cmplib=(function.funcsol);
data bmi;
set sashelp.class(keep=name age weight height);
bmindex=.;
call biomassindex(weight,height,bmindex);
run;
复制代码
几个重要一点的point;
1、 subroutine 这里可以把自变量和return值放在一起;然后通过 outargs来确定输出值是哪一个;看看例子大家一定会明白吧,所以用一个 call function 就可以完成对输出值的赋值;
proc fcmp outlib=function.funcsol.conversions;
function fromto(code $,v);
if upcase(code)='LB2KG' then r=V/2.2;
else if upcase(code)='KG2LB' then r=v*2.2;
else r=.;
return (r);
endsub;
run;
option cmplib=(function.funcsol);
data conv;
set sashelp.class(keep=name age weight);
kilos=fromto('lb2kg',weight);
pounds=fromto('kg2lb',kilos);
run;
复制代码
没有错,函数里面是可以用逻辑语句的,想怎么编就怎么编,接下来大家可能会想怎么样才能够做的更复杂,接下来的例子就是在函数里引入macro, macro本来就是为了使语句更加简化而生的,碰上个一样目的的函数过程步,不能再简化了有木有~~
%macro printit();
%put &lib &dsn;
%let lib = %sysfunc(dequote(&lib));
%let dsn = %sysfunc(dequote(&dsn));
%let num = %sysfunc(dequote(&num));
%if &num = %then %let num=max;
title2 "&lib..&dsn";
title3 "first &num observations";
proc print data=&lib..&dsn(obs=&num);
run;
%mend printit;
proc fcmp outlib=function.funcsol.utilities;
subroutine printN(lib ,dsn, num);
rc=run_macro('printit',lib,dsn,num);
endsub;
run;
复制代码
这里有一个错误使用macro的误区,我来说说我的看法吧,如果你在fcmp里面使用%macro来调用宏的话,就会存在一个编译错误的问题,具体的机制我也不甚清楚,但是可以肯定的是,这样子的宏是没法编译的,因为编译函数我觉得可能在编译宏之前,那样函数的编译就会出错;
所以使用run_macro (‘printit’,…);
来输入宏和宏变量;
剩下两个例子我个人觉得有点鸡肋,不过用处还是有的,如果你想定义非常复杂的format的话,这个还是有用的吧;
proc format;
value pounds2kg
other=[change()];
run;
options cmplib=(function.funcsol);
title2 'Weight in Kg';
proc print data=sashelp.class;
var name age weight;
format weight pounds2kg.;
run;
复制代码
大家看到了,就是起到了一个定义format里面格式的作用,把所有的格式都定义为change里面的return值,但是数据集里的值是不变的;
当然,fcmp是可以输出多个值得,用subroutine就好了不是么?
proc fcmp outlib=function.funcsol.conversions;
subroutine metric_hwbmi(h,w,mh,mw,bmi);
outargs mh,mw,bmi;
mh = h*.0254;
mw = w*.4536;
bmi = mw/(mh*mh);
endsub;
run;
options cmplib = (function.funcsol);
data multiple;
set sashelp.class(keep=name age height weight);
heightmeters=.;
weightkilos=.;
bmi=.;
call metric_hwbmi(height,weight,heightmeters,weightkilos,bmi);
run;
复制代码
%sysfunc 和 %call,能调用普通函数的工具当然也能调用我们定义的函数;
options cmplib=(function.funcsol);
%let ht = 69;
%let wt = 112.5;
%let bmi = %sysfunc(bmi(&wt,&ht));
%put &bmi;
复制代码
最后一点,定义的函数怎么去除,easy, delete 掉就好(deletefunc)
proc fcmp outlib=function.funcsol.conversions;
deletefunc lb2kgc;
deletefunc biomassindex;
run;
复制代码
定义了的函数可以一直调用而且也可以给别人使用;
但是根据我自己的试验,这个因为是储存成字符,英文版和中文版定义的函数是不能通用的哦~~希望大家能把自己的code写的越来越简单,越来越漂亮~~
翻译自:http://bbs.pinggu.org/thread-3102197-1-1.html ——Arthur:L.Carpenter(希望我理解的木有错)