【问题标题】:Problem when comparing two numeric values in SAS在 SAS 中比较两个数值时出现问题
【发布时间】:2021-05-29 12:59:38
【问题描述】:

长话短说,我需要比较两个数据集(AB)。 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 列中的两列连接起来,然后比较AB

data want;
set have;
conc=cats(id,value);
run;

这基本上适用于除一个之外的所有观察。 观察值具有A9128554507.9B9128554507.8 的值。没有格式或信息应用于变量。

                                               

但是,当在 value 变量上应用 comma32.30 格式时,我看到 AB 的值是相同的 9128554507.850000000000000000000。所以他们应该是一样的。

                               

然后我在CATS函数的文档中看到了以下内容

CATS 函数从数字中删除前导和尾随空格 使用 BESTw 格式化数值后的参数。格式。

然后我认为将数字变量转换为字符变量是一个好主意。 我是用这个宏做的:

/*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.9A9128554507.8B 的值。我不知道这两个数据集之间发生了什么? “真实”值似乎是相同的,但是当对两者应用 best. 格式时,SAS 将 A 的值四舍五入为 .9,将 B 的值四舍五入为 .8

                                             

有什么解决方法吗?尝试在数据线语句中手动输入观察结果时,我无法重现该错误。我不想将值四舍五入为预定义的小数。理想情况下,我希望将两个表的值动态截断为number of actual decimal - 1(例如3462829.374 变为3462829.3718726347.39 变为18726347.3),然后比较它们。

【问题讨论】:

  • 我认为目标是比较它们,那么为什么要连接两个变量呢?为什么不直接使用原始的两个变量进行比较?
  • 在更大的问题中,我在 A 和 B 中有大约 15 列。我将它们连接起来并使用 md5() 来计算我在两个表之间进行比较的哈希值。我只显示了变量(值),因为这是唯一导致问题的变量。
  • 我很好奇你为什么在数据步骤中使用宏函数而不是数组。这将使代码更易于使用。

标签: sas comparison


【解决方案1】:

我不知道您的更大问题是什么,但要在最后回答问题,只需使用 BEST32 将数字转换为字符串。当结果字符串包含小数点时,格式化并删除最后一个字符。

data test;
  input number expect $32. ;
  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               .

【讨论】:

  • 谢谢。我终于将 proc 与预定义的标准进行比较......你能解释一下为什么你的 put 语句中有-l 吗? (string=put(number,best32.-l);)
  • 连字符用于对齐。通常数字格式会生成右对齐的字符串。通过要求字符串从一开始就左对齐,我消除了使用 LEFT() 或 STRIP() 函数调用来删除前导空格的需要。
【解决方案2】:

你能计算出模糊并检查它吗?

* 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;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多