欧几里德距离,Scipy,纯Python和Java之间的结果不同

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了欧几里德距离,Scipy,纯Python和Java之间的结果不同相关的知识,希望对你有一定的参考价值。

我正在玩欧几里德距离度量的不同实现,我注意到我得到了Scipy,纯Python和Java的不同结果。

以下是我使用Scipy(=选项1)计算距离的方法:

distance = scipy.spatial.distance.euclidean(sample, training_vector)

这是我在论坛中发现的Python实现(选项2):

distance = math.sqrt(sum([(a - b) ** 2 for a, b in zip(training_vector, sample)]))

最后,这是我在Java中的实现(选项3):

public double distance(int[] a, int[] b) {
    assert a.length == b.length;
    double squaredDistance = 0.0;
    for(int i=0; i<a.length; i++){
        squaredDistance += Math.pow(a[i] - b[i], 2.0);
    }
    return Math.sqrt(squaredDistance);
}

sampletraining_vector都是长度为784的1-D阵列,取自MNIST数据集。我用相同的sampletraining_vector尝试了所有三种方法。问题是三种不同的方法导致三种显着不同的距离(即,选项1约为1936,选项2约为1914,选项3为1382)。有趣的是,当我在选项1和2中使用sampletraining_vector的相同参数顺序时(即将参数翻转到选项1),我得到了这两个选项的相同结果。但距离指标应该是对称的,对吧......?

还有趣的是:我将这些指标用于MNIST数据集的k-NN分类器。对于100个测试样本和2700个训练样本,我的Java实现产生了大约94%的准确度。但是,使用选项1的Python实现仅产生约75%的准确度......

你有什么想法,为什么我得到这些不同的结果?如果您有兴趣,我可以在线发布两个阵列的CSV,并在此处发布链接。

我正在使用Java 8,Python 2.7和Scipy 1.0.0。

编辑:将选项2更改为

distance = math.sqrt(sum([(float(a) - float(b)) ** 2 for a, b in zip(training_vector, sample)]))

这具有以下效果:

  • 它摆脱了ubyte溢出警告(我一定错过了这个警告......)
  • 更改选项1和2的参数顺序不再有所作为。
  • 选项2(纯Python)和3(Java)的结果现在相等

因此,这只会留下以下问题:为什么使用SciPy时结果会有所不同(即错误?)?

答案

好的,我找到了解决方案:我使用dtype=np.uint8的pandas导入了训练和测试数据集。因此,sampletraining_vector都是uint8类型的numpy数组。我将数据类型更改为np.float32,现在我的所有三个选项都给出了相同的结果。我也试过np.uint32,它也可以。

我不太清楚为什么,但显然,SciPy在使用uint8时没有给出“预期”的结果。也许SciPy有一些内部溢出?不太确定,但至少它现在有效。感谢所有帮助过的人!

以上是关于欧几里德距离,Scipy,纯Python和Java之间的结果不同的主要内容,如果未能解决你的问题,请参考以下文章

python 与scipy计算距离:欧几里得,曼哈顿,切比雪夫

Python中的多维欧几里得距离

使用空间和时间变量在 python(scipy) 中进行聚类

用scipy在其他点的截止距离内找到点

python中的测地距离变换

在 Python 中使用随机点制作欧几里德距离矩阵