比较SAS中两个数值时的问题
Problem when comparing two numeric values in SAS
长话短说,我需要比较两个数据集(A
和 B
)。 B
应该是 A
的副本,但在 Impala 服务器上。每天我都通过 SQL 传递从 Impala 服务器检索 B
到 SAS。
我正在编写一个每天 运行 的程序,以确保这两个数据集匹配 1:1。
但是,我正在努力解决数值近似值(精度)问题。
下面是A的例子:
ID
value
01
0
02
5000
03
978908.69
04
109789503.12
05
49505954.92
为了进行比较,我将两列连接到 conc
列中,然后比较 A
和 B
。
data want;
set have;
conc=cats(id,value);
run;
这基本上适用于除一个之外的所有观察结果。
观察值 A
为 9128554507.9
,B
为 9128554507.8
。没有格式或信息应用于变量。
但是,当对值变量应用 comma32.30
格式时,我看到 A
和 B
的值相同 9128554507.850000000000000000000
。所以他们应该是一样的。
然后我在CATS函数
的文档中看到了以下内容
The CATS function removes leading and trailing blanks from numeric
arguments after it formats the numeric value with the BESTw. format.
然后我认为将数字变量转换为字符变量是个好主意。
我是用这个宏做的:
/*macro to convert all numeric to char*/
%macro vars(dsn, outp);
%let list=;
%let type=;
%let dsid=%sysfunc(open(&dsn));
%let cnt=%sysfunc(attrn(&dsid,nvars));
%do i = 1 %to &cnt;
%let list=&list %sysfunc(varname(&dsid,&i));
%let type=&type %sysfunc(vartype(&dsid,&i));
%end;
%let rc=%sysfunc(close(&dsid));
data &outp(drop=
%do i = 1 %to &cnt;
%let temp=%scan(&list,&i);
_&temp
%end;);
set &dsn(rename=(
%do i = 1 %to &cnt;
%let temp=%scan(&list,&i);
&temp=_&temp
%end;));
%do j = 1 %to &cnt;
%let temp=%scan(&list,&j);
/** Change C to N for numeric to character conversion **/
%if %scan(&type,&j) = N %then %do;
/** Also change INPUT to PUT for numeric to character **/
&temp=PUT(_&temp,best.);
%end;
%else %do;
&temp=_&temp;
%end;
%end;
run;
%mend vars;
看到使用了best.
格式。不幸的是,我最终得到了与之前相同的值,9128554507.9
的 A
和 9128554507.8
的 B
的值。不知道这两个数据集之间发生了什么? “真实”值似乎是相同的,但是当对两者应用 best.
格式时,SAS 将 A
的值四舍五入为 .9
并将 B
的值四舍五入至 .8
.
有什么解决方法吗?尝试在数据线语句中手动输入观察时,我无法重现错误。我不想将值四舍五入为预定义的小数。理想情况下,我想动态地将值 运行 归类到 number of actual decimal - 1
(例如 3462829.374
变为 3462829.37
并且 18726347.39
变为 18726347.3
)两个表,然后比较它们。
我不知道你的大问题是什么,但要在最后回答问题,只需使用 BEST32 将数字转换为字符串即可。当结果字符串包含小数点时格式化并删除最后一个字符。
data test;
input number expect . ;
string=put(number,best32.-l);
if index(string,'.') then string=substrn(string,1,length(string)-1);
format number best32. ;
cards;
3462829.374 3462829.37
18726347.39 18726347.3
12345 12345
.
;
结果:
Obs number expect string
1 3462829.374 3462829.37 3462829.37
2 18726347.39 18726347.3 18726347.3
3 12345 12345 12345
4 .
你能计算模糊并检查它吗?
* retrieve a data from impala;
proc sql;
create table b as select * from connection to impala (select * from a);
data a_b_fuzz;
merge a b(rename=number=impala_number);
by id;
fuzz = number - impala_number;
run;
长话短说,我需要比较两个数据集(A
和 B
)。 B
应该是 A
的副本,但在 Impala 服务器上。每天我都通过 SQL 传递从 Impala 服务器检索 B
到 SAS。
我正在编写一个每天 运行 的程序,以确保这两个数据集匹配 1:1。 但是,我正在努力解决数值近似值(精度)问题。
下面是A的例子:
ID | value |
---|---|
01 | 0 |
02 | 5000 |
03 | 978908.69 |
04 | 109789503.12 |
05 | 49505954.92 |
为了进行比较,我将两列连接到 conc
列中,然后比较 A
和 B
。
data want;
set have;
conc=cats(id,value);
run;
这基本上适用于除一个之外的所有观察结果。
观察值 A
为 9128554507.9
,B
为 9128554507.8
。没有格式或信息应用于变量。
但是,当对值变量应用 comma32.30
格式时,我看到 A
和 B
的值相同 9128554507.850000000000000000000
。所以他们应该是一样的。
然后我在CATS函数
的文档中看到了以下内容The CATS function removes leading and trailing blanks from numeric arguments after it formats the numeric value with the BESTw. format.
然后我认为将数字变量转换为字符变量是个好主意。 我是用这个宏做的:
/*macro to convert all numeric to char*/
%macro vars(dsn, outp);
%let list=;
%let type=;
%let dsid=%sysfunc(open(&dsn));
%let cnt=%sysfunc(attrn(&dsid,nvars));
%do i = 1 %to &cnt;
%let list=&list %sysfunc(varname(&dsid,&i));
%let type=&type %sysfunc(vartype(&dsid,&i));
%end;
%let rc=%sysfunc(close(&dsid));
data &outp(drop=
%do i = 1 %to &cnt;
%let temp=%scan(&list,&i);
_&temp
%end;);
set &dsn(rename=(
%do i = 1 %to &cnt;
%let temp=%scan(&list,&i);
&temp=_&temp
%end;));
%do j = 1 %to &cnt;
%let temp=%scan(&list,&j);
/** Change C to N for numeric to character conversion **/
%if %scan(&type,&j) = N %then %do;
/** Also change INPUT to PUT for numeric to character **/
&temp=PUT(_&temp,best.);
%end;
%else %do;
&temp=_&temp;
%end;
%end;
run;
%mend vars;
看到使用了best.
格式。不幸的是,我最终得到了与之前相同的值,9128554507.9
的 A
和 9128554507.8
的 B
的值。不知道这两个数据集之间发生了什么? “真实”值似乎是相同的,但是当对两者应用 best.
格式时,SAS 将 A
的值四舍五入为 .9
并将 B
的值四舍五入至 .8
.
有什么解决方法吗?尝试在数据线语句中手动输入观察时,我无法重现错误。我不想将值四舍五入为预定义的小数。理想情况下,我想动态地将值 运行 归类到 number of actual decimal - 1
(例如 3462829.374
变为 3462829.37
并且 18726347.39
变为 18726347.3
)两个表,然后比较它们。
我不知道你的大问题是什么,但要在最后回答问题,只需使用 BEST32 将数字转换为字符串即可。当结果字符串包含小数点时格式化并删除最后一个字符。
data test;
input number expect . ;
string=put(number,best32.-l);
if index(string,'.') then string=substrn(string,1,length(string)-1);
format number best32. ;
cards;
3462829.374 3462829.37
18726347.39 18726347.3
12345 12345
.
;
结果:
Obs number expect string
1 3462829.374 3462829.37 3462829.37
2 18726347.39 18726347.3 18726347.3
3 12345 12345 12345
4 .
你能计算模糊并检查它吗?
* retrieve a data from impala;
proc sql;
create table b as select * from connection to impala (select * from a);
data a_b_fuzz;
merge a b(rename=number=impala_number);
by id;
fuzz = number - impala_number;
run;