【问题标题】:Finding the difference between two numpy arrays查找两个 numpy 数组之间的差异
【发布时间】:2020-01-11 21:17:18
【问题描述】:

我有两个来自文本文件的数组。通过观察,它看起来完全一样。然而,当我测试两个数组的等价性时,它们失败了——元素方面、形状方面等等。我使用了 numpy 测试回答了here

这是两个matrices

import numpy as np

class TextMatrixAssertions(object):
    def assertArrayEqual(self, dataX, dataY):
        x = np.loadtxt(dataX)
        y = np.loadtxt(dataY)

        if not np.array_equal(x, y):
            raise Exception("array_equal fail.")

        if not np.array_equiv(x, y):
            raise Exception("array_equiv fail.")

        if not np.allclose(x, y):
            raise Exception("allclose fail.")

dataX = "MyMatrix.txt"
dataY = "MyMatrix2.txt"
test = TextMatrixAssertions()
test.assertArrayEqual(dataX, dataY)

我想知道这两个数组之间是否真的存在一些差异,或者如果没有,是什么导致了失败。

【问题讨论】:

  • 大概打印您的值会使它们看起来相同?我会尝试做一个print(repr(x))print(repr(y)),看看是否可以更清楚地了解这些值的不同之处。 docs.python.org/3/library/functions.html#repr 尝试打印“传递给 eval() 时会产生具有相同值的对象的字符串”
  • 您确实意识到您的raise 语句中止了您的方法的执行,对吧?因此,如果array_equal() 返回False,则永远无法到达allclose()
  • 是的,我评论其他人以检查其他人。

标签: python arrays numpy matrix


【解决方案1】:

它们不相等,它们有 54 个不同的元素。

np.sum(x!=y)

54

要找出不同的元素,您可以这样做:

np.where(x!=y)


(array([  1,   5,   7,  11,  19,  24,  32,  48,  82,  92,  97, 111, 114,
        119, 128, 137, 138, 146, 153, 154, 162, 165, 170, 186, 188, 204,
        215, 246, 256, 276, 294, 300, 305, 316, 318, 333, 360, 361, 390,
        419, 420, 421, 423, 428, 429, 429, 439, 448, 460, 465, 467, 471,
        474, 487]),
 array([18, 18, 18, 17, 17, 16, 15, 12,  8,  6,  5,  4,  3,  3,  2,  1,  1,
        26,  0, 25, 24, 24, 24, 23, 22, 20, 20, 17, 16, 14, 11, 11, 11, 10,
        10,  9,  7,  7,  5,  1,  1,  1, 26,  1,  0, 25, 23, 21, 19, 18, 18,
        17, 17, 14]))

【讨论】:

  • 如何找到他们的索引?
【解决方案2】:

您应该首先尝试使用更小更简单的矩阵来测试您的代码。

例如:

import numpy as np
from io import StringIO



class TextMatrixAssertions(object):
    def assertArrayEqual(self, dataX, dataY):
        x = np.loadtxt(dataX)
        y = np.loadtxt(dataY)

        if not np.array_equal(x, y):
            raise Exception("array_equal fail.")

        if not np.array_equiv(x, y):
            raise Exception("array_equiv fail.")

        if not np.allclose(x, y):
            raise Exception("allclose fail.")

        return True

a = StringIO(u"0 1\n2 3")
b = StringIO(u"0 1\n2 3")
test = TextMatrixAssertions()
test.assertArrayEqual(a,b)

输出

True

所以我猜你的问题出在你的文件上,而不是你的代码上。您也可以尝试在 x 和 y 中加载相同的文件并查看输出。

要查看哪些元素不同,您可以尝试not_equal

例子

a = StringIO(u"0 1\n2 3")
c = StringIO(u"0 1\n2 4")
x = np.loadtxt(a)
y = np.loadtxt(c)
np.not_equal(x,y)

Output

array([[False, False],
       [False,  True]])

【讨论】:

  • 是的。我知道函数没有问题,因为我在我测试的其他数组上使用它。但是对于这个特定的矩阵,我只是看不到差异。
  • 然后用not_equal函数看看有什么不同的元素
【解决方案3】:

另一种解决方案。您可以看到不相等的元素的值。如果您运行以下代码,您将看到具有 nan 值的元素不相等,因此会引发异常。

import numpy as np

class TextMatrixAssertions(object):
    def assertArrayEqual(self, dataX, dataY):
        x = np.loadtxt(dataX)
        y = np.loadtxt(dataY)

        if not np.array_equal(x, y):
            not_equal_idx = np.where(x != y)
            for idx1, idx2 in zip(not_equal_idx[0],not_equal_idx[1]):
                print(x[idx1][idx2])
                print(y[idx1][idx2])
            raise Exception("array_equal fail.")

        if not np.array_equiv(x, y):
            raise Exception("array_equiv fail.")

        if not np.allclose(x, y):
            raise Exception("allclose fail.")

dataX = "MyMatrix.txt"
dataY = "MyMatrix2.txt"
test = TextMatrixAssertions()
test.assertArrayEqual(dataX, dataY)

输出:

nan
nan
nan
...
nan

【讨论】:

  • 这太复杂了。
  • @Nils Werner,你能评论一下为什么这很复杂吗?这个想法是向 OP 解释他的代码没有按预期运行的原因。我的代码如何使对此的理解复杂化?
  • 使用索引来访问不同的元素并不是最有效的,for 循环是不必要的,并且使用 x[i][j] 不好的样式并且可能会产生意想不到的后果。
  • 我不懂你。当输入文件为空或长度不同时,您的意思可能是一些极端情况。但是,对于 OP 提供的输入以及为了向他解释代码引发异常的原因,我的代码完成了这项工作。
  • 是的,它只是不必要的复杂 :-) idx = x != y; print(x[idx], y[idx]) 也是如此,但更简单、更快。