今天群group里有一个人问:如何将1/4转换成数值型的0.25?
有一位小可爱直接通过分隔符"/"拆分出分子分母然后相除,我想说的是这样不一定是错误的,只是关注到她好几次这样简单粗暴的解决问题,显得有些可爱。虽然有时候能解决问题,但是考虑的不全面。
至于读者为什么会有这样的一个问题,我不清楚,在工作中好像也没有遇到,便去搜了一下,SAS官网上好像没有直接的函数能够解决这样的问题,但是也不是说就不能解决了。
方法一:
就像小可爱说的直接拆分相除,但是的话,如果原始数据不是分数形式,比如说现在有两个字符型值,一个是"1/4",一个是“0.75”,如果只是单纯的相除的话,那么对于0.75,在计算的时候,会报这样一个Note:
data test;
c="0.75";
newvar = input(scan(c, 1, "/"), best.) / input(scan(c, 2, "/"),??best.);
run;

所以为了避免这种情况,你要么提前加一个if index(c,"/"),要么采用下面这种写法:
data test;
c="0.75";
newvar = input(scan(c, 1, "/"), best.) / coalesce(input(scan(c, 2, "/"), ?? best.), 1);
d="1/4";
newvar2 = input(scan(d, 1, "/"), best.) / coalesce(input(scan(d, 2, "/"), ?? best.), 1);
run;

但是不知道会不会有“1/0”的情况,如果有的话,还是需要判断分母不为0.
这里顺便介绍一下COALESCE函数,作用就是返回一系列数值型列表里面的第一个非空或者非缺失值。这好像有的面试也会问到。
data test;
CC=coalesce(0,1);
DD=coalesce(.,2,1);
EE=coalesce(.B,8,1);
FF=coalesce(.,.,.);
run;

注意EE=coalesce(.B,8,1);这里的.B也是数值型,也是非空的,但是还是选到了8,说明了要数字形式的才会输出。
对应的搜索字符型表达式的函数就是COALESCEC。
方法二:
data test;
c="0.75";
newvar = input(resolve( '%sysevalf(' || c || ')' ),best.);
d="1/4";
newvar2 = input(resolve( '%sysevalf(' || d || ')' ),best.);
run;

首先介绍resolve函数:
Returns the resolved value of the argument after the argument has been processed by the macro facility.
resolve的一个作用就是返回一个字符文本,而这个字符文本是来自macro facility解析之后的一个值。语法格式就是:
variable = RESOLVE(argument);
RESOLVE能处理的三种类型的参数如下
● DATA step variable names
● Text enclosed in single quotes
● Character expressions
用单引号括起来的一个文本,看一个例子:
%let test=5;
data b;
w = &test;
y = resolve('&test');
run;

那么在本文中的例子,应该是属于第三种类型
所以上面的resolve( '%sysevalf(' || d || ')' ),简化一下就是
' %sysevalf(' 这是一起的,用单引号括起来防止被宏扫描器发现,
然后拼接符拼上d变量的值,注意不会把D的双引号也拼过来啊!就跟我们平时用拼接符拼接变量是一样的,除非双引号里面还有引号才会拼上引号。
最后再拼上')'
所以最后运行的是resolve(%sysevalf(1/4));
而%sysevalf的作用就是使用浮点运算计算算术和逻辑表达式。
比如下面这样
%let x = %sysevalf(7/3);
%put Using SYSEVALF &=x;

最后resovle返回的就是%sysevalf计算后的值,也就是0.25,但是是字符型的,我们只要input一下就可以了。
同时,在查阅资料的过程中,发现在SAS中有一个直接将数值型转换成分数的功能,就是FRACTw. Format。
这个W是指定输出的宽度。
data test;
do a=0.666,1.25,0.75,0.66666666666;
b=put(a,fract10.);
output;
end;
run;

但是好像不会转换成假分数,而且如果是0.5的话,只会转换成1/2,但是50/100也是0.5。
网友评论