sp的工作都是这样吗?忙的时候很忙,闲的时候很闲。
1. Functions: tranwrd & transtrn
TRANWRD(source, target, replacement):替代目标字符串中的指定字符。
TRANSTRN(source, target, replacement): 替代或者移除目标字符串中的指定字符。
这在知道替换词或者替换符号的时候很好用,并且两个作用相同。唯一不同的是对于指定word长度为0时,tranwrd会替换为空白字符,transtrn会替换为空。
data holiday;
set sashelp.holiday;
/****Replace all occurence of "_" with "" ****/
category1a=tranwrd(category,"_",trimn(""));
category1b=transtrn(category,"_",trimn(""));
/****Replace all occurence of "_" with "-" ****/
category2a=tranwrd(category,"_","-");
category2b=transtrn(category,"_","-");
/****Replace all occurence of "US" with "United States" ****/
category3a=tranwrd(category,"US","United States");
category3b=transtrn(category,"US","United States");
run;
2. Functions: whichc & whichn
WHICHC(string, value-1 <, value-2, ...>): 在给定字符串value-n中搜索string并返回对应的索引值。
WHICHN(argument, value-1 <, value-2, ...>):在给定数值value-n中搜索值并返回对应的索引值。
可以根据已知的分类直接赋值,类似作用的写法或函数有很多。
data class;
set sashelp.class;
sexn = whichc(sex,"F","M");
run;
但是需要注意的是,返回的都是索引值,索引值都是从1开始,所以最低的赋值为1,如果找不到对应的值则为0。这个在给arm或者treatment分组的时候很合适,不需要多个if-else statement。但是如果value太多,还是做成format的形式更便捷。
/********Create dummy treatment dataset********/
data dummy_trt;
do subject = 1 to 5;
trt = cats("P1CH",subject);
output;
end;
run;
/********assign number of treatment group********/
data dummy_trtn;
set dummy_trt;
array treatment(4) $8 _temporary_ ("P1CH1","P1CH2","P1CH3","P1CH4");
trtn = whichc(trt, of treatment[*]);
/* trtn = whichc(trt,"P1CH1","P1CH2","P1CH3","P1CH4"); */
run;
3. 建议code起始都加一句
proc dataset lib=work memtype=data kill nolist; quit;
这样做的好处是在最后multirun时,不会因为别人程序生成的数据集影响到自己的程序,即先清空work环境下所有的临时数据集。
4. ifc & ifn 让code变得简洁
IFC/IFN (logical-expression, value-returned-when-true, value-returned-when-false
<, value-returned-when-missing>)
两个用法的区别是return的是字符串还是数值,使用起来很简洁。
age_group = ifc(age^=. and age>60,"> 60 years","<= 60 years");
5. ifc & ifn 遇上zero or missing numeric variable
Safety output会经常要计算各个分类变量的受试者患者数n,以及在人群N中的占比,并以 n(%) 来展示结果。当人群N为各个treatment group时,会遇到某一个或几个组还没有患者enroll,此时N就为0,而分母在除法中是不能为0的。
data aaa;
a=2; b=3; output;
a=5; b=0; output;
a=0; b=0; output;
a=.; b=5; output;
run;
/***original code: calculate percentage c ***/
data bbb;
set aaa;
length c 8.;
c = ifn(b>0, a/b*100, .);
run;
a) clean note: Division by zero detected
按IFN的逻辑,最开始的代码没有毛病,只有当分母b大于0的时候,才会进行除法运算,我没查到出现zero detected的原理是什么,但是clean note比较容易,只要改为用函数运算就好。
但是依旧会报missing value的note。
/***clean note: Division by zero detected ***/
data bbb;
set aaa;
length c 8.;
c = ifn(b>0 and a^=. , divide(a/b)*100, .);
run;
b) clean note: Missing values
即使第一个参数的逻辑条件绕过缺失值,只要后面true或false涉及数值运算,这条note就会始终出现。虽然不影响output的结果,但是这种note也是不允许出现的。
这种情况 IFC/IFN 就不再适用,而是要换回传统的 if-else statement。
/***clean note: Missing values ***/
data bbb;
set aaa;
length c 8.;
if b>0 and a^=. then c = divide(a/b)*100 ;
else c = .;
run;
虽然清空了sas log, 但为什么出现这些问题,至今我没还没有找到答案,或许哪位民间高人可以指点一下?