numpy精度:比较数字时的问题

时间:2012-01-09 17:20:33

标签: python numpy linear-algebra

首先是一些背景知识。我找到了一个实对称矩阵的特征值和特征向量,其中行总和为0.更具体地说,一旦我找到一个特征向量,我使用$ argsort $来找到对一个特征值进行排序的排列并将置换应用于原始矩阵。

现在,我使用numpy包在python中实现了代码。代码本身是递归的,如果它在特征向量中找到一组相等的值,它将提取对应于我们具有相等值的索引的对称子矩阵,并在该矩阵上重新应用该算法。

虽然这一切都非常好,而且大多是笨拙的工作,当一堆应该与特征向量中的相等条目相对应的索引未被识别为具有相等的值时,我感到惊讶。问题是这些值是通过某种算法计算机器精度的(可能是Lanczos,但我并不完全熟悉numpy)。这是一个示例输出,其中我明确检查了特征向量中两个条目之间的差异:

    >>> T=spectral.seriation(A,index)

    columns [ 0  1  2  3  4  5  6  7  8  9 10 11]

    [  3.30289130e-01  -2.75240941e-01  -2.75240941e-01   3.30289130e-01
    -2.75240941e-01   3.30289130e-01  -2.75240941e-01   3.30289130e-01
    3.30289130e-01  -2.75240941e-01  -1.69794463e-16  -2.75240941e-01]

    [ 4  6  9  1  2 11 10  0  5  7  8  3]

    difference   -5.55111512313e-17

例程系列()是一个递归函数。浮点数组是正在考虑的特征向量,下面的数组给出了列的排序顺序。请注意,列[4,6,9,1,2,11]具有相同的值。然而,特征向量和特征值计算总是近似的,实际上,当我输出第9列和第2列中的条目之间的差异时,它是非零的。在算法应该分组[4,6,9,1,2,11]的情况下,它只将[4,6,9]组合在一起,并将其余的组合放在另一组中,将一个扳手投入工作中。

所以问题是这样的:有没有一种方法可以在numpy中执行任意精度计算?如果做不到这一点,这个问题的“好”解决方法是什么?

另外,我应该提一下,可以在数学上证明这些条目必须相同。这是矩阵的一个属性,但希望与此问题没有密切关系。

4 个答案:

答案 0 :(得分:4)

双打并不是真正的数字[甚至不合理]。每个范围都有无数的有理数[嗯,每个范围至少有两个元素,确切地说],但只有有限数量的位来表示它们。
因此,对于“精确”计算,应该会出现一些舍入误差。

有关更多信息,您可能需要阅读what every computer scientist should know about floating-point arithmetic

答案 1 :(得分:2)

当执行相减大小的两个浮点数的减法时,精度应该不是问题,即如果[2]和[9]真的相同则差值将为零。

我怀疑实际情况是默认情况下输出显示数字到8位小数但超出数字不同,通常一个double有大约16位小数的精度,(找出运行{{1}获得机器epsilon,它给出了可能的最小数量超过1)

尝试使用numpy.finfo(numpy.float).eps的输出格式检查数字。

如果它们确实不同但您对7d.p的相似性感到满意,那么您可以使用类似"%.16f\n%.16f" % myarray[[2, 9]]的内容截断结果。

或者,如果您想预处理数据,那么您可以使用以下内容(尽管可能有更好的方法)。

numpy.around(differences, 7)

答案 2 :(得分:2)

检查numpy.allclosenumpy.isclose函数,以便在容差范围内测试相等性。

答案 3 :(得分:1)

如果您希望几乎相等的元素的索引达到给定的容差,您可以执行以下操作:

def almost_matches(x, array, rtol=1e-05, atol=1e-08):
    answer = []
    for y in xrange(len(array)):
        if abs(x-array[y]) <= (atol + rtol * abs(array[y])):
            answer.append(y)
    return answer

(使用与numpy.allclose()使用相同的近似比较)

>>> a = [3.30289130e-01,  -2.75240941e-01,  -2.75240941e-01,   3.30289130e-01, -2.75240941e-01, 3.30289130e-01,  -2.75240941e-01,   3.30289130e-01, 3.30289130e-01,  -2.75240941e-01,  -1.69794463e-16,  -2.75240941e-01]
>>> almost_matches(min(a), a)
[1, 2, 4, 6, 9, 11]