SAS应用:都是小数点惹的祸

2020/09/29 10:54

SAS应用:都是小数点惹的祸

今天有人用了两种方法通过分组求平均数问题,发现结果不一样。为了说明问题,我自己简单地造了些数据,如下:

data dup;
input  id  date  field  value ;
cards;
1  2  0.0001  10
1  2  0.0001  10
1  2  0.00001  10
1  2  0.00001000001  10
1  3  0.00001  10
1  3  0.00001  10
1  3  0.00003  10
1  3  0.00003  10
1  3  0.00003  10
;
run;
proc sql;

create table NoDup1 as
select unique id, date, field, avg(value) as value from Dup group by id, date, field;
quit;   ;
*method 2;
proc means data = Dup nway ;
class  id date field;
var value;
output out = NoDup2(drop = _type_ _freq_) mean = value;
run;
初一看来,好像代码没什么问题,应该结果一致,然而结果运行后,用sql得到的结果与proc步不一样,这是为什么? 似乎这是SAS的错误,哈哈这个多么伟大的一个发现啊!  SAS可以说是总多行业里面的标准,竟然也会错。   其实这不是第一次发现这类问题。 以前也遇到过同样的一个问题,就是:

data ex;
do i= 0.05 to 0.15 by 0.01;
if i=0.1 then output;
end;
run;

这个代码运行后,ex数据集是空的,是不是SAS出错了。后来发现这是由于计算机存储小数的浮点问题,循环5次后,i应该等于0.1,实际上非常接近0.1,是个近似值,并不是等于0.1,因此并无数据输出到ex里面。

那么回到上面的那个问题,根本原因是proc sql和proc mean步对数的小数点处理不同,proc mean考虑到小数点多于sql, 因此会导致nodup1比nodup2少一条观察。下面我提供第三种解决此类问题的代码,data步,也是商业大型数据的常用方法:

data nodup3;
set dup;
by id date field;
if  first.field then  do; num=0;mean=0;end;
num+1; mean+value;
if last.field then do;  value=mean/num; drop num mean; output; end;
run;

这个也是和proc mean步结果是一样的。

有时候也许不需要考虑没必要的小数位,可以用函数round,int,ceil等,还有一种方法就是把需要分组和比较大小的非整数用format格式化一下。

一般来说,我如果发现SAS运行结果和我想的不一样,可以归结于两点:1,自己的代码有问题;2,小数点问题。

免费直播

    精选课程 更多

    注册电脑版

    版权所有 2003-2020 广州环球青藤科技发展有限公司