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

Python numpy中的精度:比较数字时的问题,python,numpy,linear-algebra,Python,Numpy,Linear Algebra,先来点背景知识。我正在寻找实对称矩阵的特征值和特征向量,其中行和为0。更具体地说,一旦我找到一个特征向量,我就使用$argsort$来找到对其中一个特征值进行排序的排列,并将排列应用于原始矩阵 现在,我用python实现了代码,使用numpy包。代码本身是递归的,如果它在特征向量中找到一组相等的值,它将提取对应于我们具有相等值的索引的对称子矩阵,并在该矩阵上再次应用该算法 虽然这一切都很好,而且大部分是繁重的工作,但当一组本应对应于特征向量中相等项的索引没有被识别为具有相等值时,我感到惊讶。问题

先来点背景知识。我正在寻找实对称矩阵的特征值和特征向量,其中行和为0。更具体地说,一旦我找到一个特征向量,我就使用$argsort$来找到对其中一个特征值进行排序的排列,并将排列应用于原始矩阵

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

虽然这一切都很好,而且大部分是繁重的工作,但当一组本应对应于特征向量中相等项的索引没有被识别为具有相等值时,我感到惊讶。问题是这些值是通过某种算法(可能是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
例程serial()是一个递归函数。浮点数组是考虑中的特征向量,下面的数组给出列的排序顺序。请注意,[4,6,9,1,2,11]列的值相同。然而,特征向量和特征值的计算总是近似的,事实上,当我输出第9列和第2列中的条目之间的差值时,它是非零的。如果算法应该对[4,6,9,1,2,11]进行分组,那么它只会对[4,6,9]进行分组,并将其余的放入另一个组中,这给工作带来了麻烦

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


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

双精度不完全是实数[甚至不是有理数]。在每个范围内都有无穷多的有理数[确切地说,每个范围至少有两个元素],但只有有限数量的位来表示它们。
因此,对于“精确”计算,您应该会遇到一些舍入误差


要了解更多信息,您可能需要阅读

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

我怀疑实际情况是,默认情况下,输出显示的数字为8位小数,但除此之外,数字不同,通常双精度精度约为16位小数(查找run
numpy.finfo(numpy.float).eps
以获取机器ε,该机器ε给出了1以上的最小可能数字)

尝试使用输出格式
“%.16f\n%.16f”%myarray[[2,9]]]
检查数字

如果它们确实不同,但您对7d.p的相似性感到满意,那么您可以使用类似于
numpy.around(differences,7)
的方法来截断结果

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


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

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
numpy.isclose
函数以测试公差范围内的相等性。

事实上,如果只是为了找到特征值和特征向量,我可以接受精度损失。毕竟,它们不一定是理性的,甚至不是终止小数。然而,对我来说重要的是,程序应该忽略这些舍入错误引起的微小差异。否则,正如我们在上面的例子中看到的,列的分区会出错。正如@amit已经说过的,千万不要检查它是否与浮点数相等。检查它们是否在一定的容错范围内。如果您想为其使用
numpy
函数,请使用
numpy.allclose(a,b)
而不是
a==b
。不过,为了更直接地回答您的问题,numpy不支持任意精度。(你可以用
decimal
s的对象数组来伪造它,但是1)这破坏了numpy数组的全部功能,2)
numpy.linalg
使用lapack,它不支持任意精度,所以在这种情况下你不会得到任何东西。)
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
>>> 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]