SAS中文论坛

标题: 都是小数点惹的祸 [打印本页]

作者: shiyiming    时间: 2010-10-22 13:32
标题: 都是小数点惹的祸
From sxlion's blog on Sohu

<div style="FONT-SIZE: 14px; LINE-HEIGHT: 160%">
<p>&nbsp;&nbsp;&nbsp;&nbsp;今天mymas上有人用了两种方法通过分组求平均数问题,发现结果不一样。为了说明问题,我自己简单地造了些数据,如下:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;data dup;<br />input&nbsp; id&nbsp; date&nbsp; field&nbsp; value ;<br />cards;<br />1&nbsp; 2&nbsp; 0.0001&nbsp; 10<br />1&nbsp; 2&nbsp; 0.0001&nbsp; 10<br />1&nbsp; 2&nbsp; 0.00001&nbsp; 10<br />1&nbsp; 2&nbsp; 0.00001000001&nbsp; 10<br />1&nbsp; 3&nbsp; 0.00001&nbsp; 10<br />1&nbsp; 3&nbsp; 0.00001&nbsp; 10<br />1&nbsp; 3&nbsp; 0.00003&nbsp; 10<br />1&nbsp; 3&nbsp; 0.00003&nbsp; 10<br />1&nbsp; 3&nbsp; 0.00003&nbsp; 10<br />;<br />run;<br />proc sql;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;create table NoDup1 as<br />&nbsp; &nbsp; &nbsp; select unique id, date, field, avg(value) as value from Dup group by id, date, field; <br />&nbsp; &nbsp;quit;&nbsp;&nbsp;&nbsp;;<br />*method 2;<br />proc means data = Dup nway ;<br />&nbsp; &nbsp;class&nbsp; id date field;<br />&nbsp; &nbsp;var value;<br />&nbsp; &nbsp;output out = NoDup2(drop = _type_ _freq_) mean = value;<br />run; <br />初一看来,好像代码没什么问题,应该结果一致,然而结果运行后,用sql得到的结果与proc步不一样,这是为什么? 似乎这是SAS的错误,哈哈这个多么伟大的一个发现啊!&nbsp;<img alt="大笑" src="http://js3.pp.sohu.com.cn/ppp/images/emotion/base/spit.gif" />&nbsp; SAS可以说是总多行业里面的标准,竟然也会错。&nbsp;<img alt="强" src="http://js3.pp.sohu.com.cn/ppp/images/emotion/base/strong.gif" />&nbsp;&nbsp;<img alt="酷" src="http://js3.pp.sohu.com.cn/ppp/images/emotion/base/cool2.gif" />&nbsp;&nbsp;<img alt="赞" src="http://js3.pp.sohu.com.cn/ppp/images/emotion/base/good.gif" />&nbsp;&nbsp;&nbsp;&nbsp;其实这不是第一次发现这类问题。<img alt="微笑" src="http://js3.pp.sohu.com.cn/ppp/images/emotion/base/smile.gif" />&nbsp;以前也遇到过同样的一个问题,就是:</p>
<p>&nbsp;&nbsp;&nbsp;data ex;<br />&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;do i= 0.05 to 0.15 by 0.01;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if i=0.1 then output;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;<br />&nbsp;run;</p>
<p>&nbsp;&nbsp;&nbsp;这个代码运行后,ex数据集是空的,是不是SAS出错了。后来发现这是由于计算机存储小数的浮点问题,循环5次后,i应该等于0.1,实际上非常接近0.1,是个近似值,并不是等于0.1,因此并无数据输出到ex里面。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 那么回到上面的那个问题,根本原因是proc sql和proc mean步对数的小数点处理不同,proc mean考虑到小数点多于sql, 因此会导致nodup1比nodup2少一条观察。下面我提供第三种解决此类问题的代码,data步,也是商业大型数据的常用方法:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data nodup3;<br />&nbsp; &nbsp; &nbsp;set dup;<br />&nbsp; &nbsp; by id date field;<br />&nbsp; &nbsp; if&nbsp; first.field then&nbsp; do; num=0;mean=0;end;<br />&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;num+1; mean+value;<br />&nbsp; &nbsp; if last.field then do;&nbsp; value=mean/num; drop num mean; output; end;<br />run;</p>
<p>这个也是和proc mean步结果是一样的。</p>
<p>有时候也许不需要考虑没必要的小数位,可以用函数round,int,ceil等,还有一种方法就是把需要分组和比较大小的非整数用format格式化一下。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般来说,我如果发现SAS运行结果和我想的不一样,可以归结于两点:1,自己的代码有问题;2,小数点问题。</p></div>




欢迎光临 SAS中文论坛 (https://mysas.net/forum/) Powered by Discuz! X3.2