【问题标题】:canberra distance - inconsistent results堪培拉距离 - 结果不一致
【发布时间】:2016-12-18 02:14:10
【问题描述】:

我试图了解我计算堪培拉距离时发生了什么。我编写了自己的简单canberra.distance 函数,但结果与dist 函数不一致。我在我的函数中添加了选项na.rm = T,以便能够在分母为零时计算总和。从?dist 我了解到他们使用类似的方法:Terms with zero numerator and denominator are omitted from the sum and treated as if the values were missing.

canberra.distance <- function(a, b){
  sum( (abs(a - b)) / (abs(a) + abs(b)), na.rm = T )
}

a <- c(0, 1, 0, 0, 1)
b <- c(1, 0, 1, 0, 1)
canberra.distance(a, b)
> 3 
# the result that I expected
dist(rbind(a, b), method = "canberra")
> 3.75 


a <- c(0, 1, 0, 0)
b <- c(1, 0, 1, 0)
canberra.distance(a, b)
> 3
# the result that I expected
dist(rbind(a, b), method = "canberra")
> 4   

a <- c(0, 1, 0)
b <- c(1, 0, 1)
canberra.distance(a, b)
> 3
dist(rbind(a, b), method = "canberra")
> 3
# now the results are the same

0-0 和 1-1 对似乎有问题。在第一种情况 (0-0) 中,分子和分母都等于 0,应该省略这对。在第二种情况下(1-1),分子为 0,但分母不是,则项也为 0,总和不应改变。

我在这里错过了什么?

编辑: 为了符合R定义,函数canberra.distance可以修改如下:

canberra.distance <- function(a, b){
  sum( abs(a - b) / abs(a + b), na.rm = T )
}

但是,结果和以前一样。

【问题讨论】:

  • 我认为您可能偶然发现了基础 R 中的一个错误。我不确定,但 Wolfram Alpha agrees with you。不幸的是,我找不到权威参考,但根据 Wikipedia 和 Wolfram,您的实现似乎是正确的。
  • 事实上,documentation of dist 将堪培拉距离定义为 sum(|x_i - y_i| / |x_i + y_i|)(这与您和 Wolfram 的不同)。它还指出“[t]his 旨在用于非负值(例如计数):取分母的绝对值是 1998 R 修改以避免负距离。” — 所以 R 的定义被证明是不同的。
  • @KonradRudolph 感谢您的回复!我编辑了我的帖子。使用 R 定义的堪培拉距离不一致仍然存在,所以我认为这不是问题。
  • 是的,我怀疑文档中提到的“1998 R 修改”不仅仅是删除负值。实际上,文档可能旨在说明“此实现以未指定的方式不同于其他定义,因此产生不同的结果”。查看 C 源代码可以澄清这一点。无论如何,至少它的记录很差。

标签: r distance


【解决方案1】:

这可能会说明差异。据我所知,这是为计算距离而运行的实际代码

static double R_canberra(double *x, int nr, int nc, int i1, int i2)
{
    double dev, dist, sum, diff;
    int count, j;

    count = 0;
    dist = 0;
    for(j = 0 ; j < nc ; j++) {
    if(both_non_NA(x[i1], x[i2])) {
        sum = fabs(x[i1] + x[i2]);
        diff = fabs(x[i1] - x[i2]);
        if (sum > DBL_MIN || diff > DBL_MIN) {
        dev = diff/sum;
        if(!ISNAN(dev) ||
           (!R_FINITE(diff) && diff == sum &&
            /* use Inf = lim x -> oo */ (int) (dev = 1.))) {
            dist += dev;
            count++;
        }
        }
    }
    i1 += nr;
    i2 += nr;
    }
    if(count == 0) return NA_REAL;
    if(count != nc) dist /= ((double)count/nc);
    return dist;
}

我认为罪魁祸首是这条线

if(!ISNAN(dev) ||
               (!R_FINITE(diff) && diff == sum &&
                /* use Inf = lim x -> oo */ (int) (dev = 1.))) 

处理特殊情况,可能没有记录。

【讨论】:

  • 感谢您的回答。不幸的是,我对 C++ 不是很熟练,所以我不确定这些特殊情况是怎么回事。你能解释一下吗?
  • 该行包含一个特殊情况,如果两个值相同diff == sum,那么它会将分子加一,因为它设置了dev=1。但是,为什么代码首先通过diff &gt; DBL_MIN 对我来说有点不清楚。也许浮点转换/精度有问题?
  • 嗯,在分子上加一可以解释 1-1 对和距离值为 4 的情况。但是我看不出这如何涉及 0-0 对的情况。有什么想法吗?
  • 对于 0-0 对,总和为零,差也为零,因此diff == sum 部分仍会触发。
猜你喜欢
  • 1970-01-01
  • 2023-01-31
  • 2020-04-20
  • 2015-09-02
  • 1970-01-01
  • 2016-12-19
  • 2012-06-15
  • 2013-01-15
  • 2012-08-03
相关资源
最近更新 更多