Tengo algo de código que realiza un gradiente de verificación. Recientemente, he cambiado
la función de comparación de math.isclose a numpy.isclose más consistentemente el uso de numpy, y para mi sorpresa, algunas de mis afirmaciones comenzó a fallar.

He reducido el ejemplo en el código siguiente

import math
import numpy

a = 0.27415101
b = 0.27415383
rel_tol = 1e-5
abs_tol = 1e-6

print(math.isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol))
print(numpy.isclose(a, b, rtol=rel_tol, atol=abs_tol))

Salida

False
True

Aparentemente matemáticas.isclose y numpy.isclose son muy diferentes.

Cuál debo usar, y por qué?

Python: 3.6.3, Numpy: 1.13.3.

OriginalEl autor Neo | 2018-01-08

3 Comentarios

  1. 14

    Que se ha discutido recientemente en GitHub.
    Las fórmulas utilizadas en matemáticas y
    colección son de hecho diferentes:

    # This is numpy.isclose
    abs(a - b) <= (atol + rtol * abs(b))
    
    # This is math.isclose
    abs(a - b) <= max(rtol * max(abs(a), abs(b)), atol)

    Como se puede ver, numpy versión es asimétrica (y está claramente establecido en el doc).
    En la parte superior de que, atol puede interferir con la rtol, provocando la falsa igualdad, como en su caso.

    No es difícil llegar con un ejemplo, cuando numpy.isclose la asimetría de incendios:

    a = 0.142253
    b = 0.142219
    rel_tol = 1e-4
    abs_tol = 1.9776e-05
    print(np.isclose(a, b, rtol=rel_tol, atol=abs_tol))  # False
    print(np.isclose(b, a, rtol=rel_tol, atol=abs_tol))  # True

    math.isclose no sufre de cualquiera de estos problemas, por lo tanto es preferible:

    print(math.isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol))  # False
    print(math.isclose(b, a, rel_tol=rel_tol, abs_tol=abs_tol))  # False

    No se ha decidido cuál es la adecuada revisión debe ser
    (se ha sugerido introducir otra función o agregar un argumento adicional o poner una nueva versión de np.isclose a numpy.__future__),
    pero hasta ahora sólo la documentación ha sido extendido.

    No es estrictamente un bug, pero la incompatibilidad es poco conveniente, y hay ventajas en el math módulo de la semántica, por lo que les gustaría encontrar una manera de cambiar las cosas.
    Depende de la definición de un bug. Si la compatibilidad no era un problema, no hay ninguna razón para mantener una fórmula existente y no cambiar a math versión.
    Incompatibilidad con algo que ni siquiera existían cuando numpy.isclose fue creado, que no fue diseñado para la compatibilidad con numpy.isclose, definitivamente no es algo que me gustaría clasificar como un error.
    Me refería a la compatibilidad hacia atrás. El elegido aplicación es peor, lo suficiente como para que me llame es un error. Si hipotéticamente numpy importaba el código existente de la base, lo que podría ser la razón para no cambiar?
    ¿Por qué la simetría ser preferible? Si b es un buen valor, mientras que un está sujeto a desconocidos a los errores de redondeo, entonces la medida de error relativo es relativo a la b y no para el uso incontrolado de valor en un como base para la medición. Así que la versión asimétrica es el método preferido para este uso. Si ni un, ni b es un buen valor, entonces lo que es uno tratando de calcular cuando con isclose? “Son estos dos valores con errores, tanto en lo malo del mismo modo?”

    OriginalEl autor Maxim

  2. 7

    Para finito de valores, numpy.isclose utiliza

    absolute(a - b) <= (atol + rtol * absolute(b))

    y matemáticas.isclose utiliza

    abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

    numpy suma la absoluta y relativa de los factores, y se aplica rtol a b en lugar de los de mayor magnitud argumento. Las funciones son similares en espíritu, y usted estará bien usando, o utilizando su propio personalizado de verificación.

    numpy.isclose vectorizes a través de matrices y math.isclose no, por supuesto, por lo que probablemente será el factor decisivo a la hora de trabajar con matrices. math.isclose‘s de verificación tiene sus ventajas (simétrica de la prueba es generalmente menos sorprendente, por defecto abs_tol de 0 evita hacer suposiciones acerca de la escala de entrada, max en lugar de + evita a veces haciendo la tolerancia de dos veces tan alto como se esperaba), y se puede implementar una matriz compatible con la versión de math.isclose bastante fácilmente. La traducción de la matemáticas.isclose código fuente a algo numpy-compatible:

    def math_compatible_isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
        a, b = numpy.asarray(a), numpy.asarray(b)
    
        equal = (a == b)
        either_infinite = numpy.isinf(a) | numpy.isinf(b)
    
        abs_diff = numpy.abs(b-a)
        b_rtol_check = (abs_diff <= numpy.abs(rel_tol * b))
        a_rtol_check = (abs_diff <= numpy.abs(rel_tol * a))
        atol_check = (abs_diff <= abs_tol)
        tol_check = atol_check | a_rtol_check | b_rtol_check
    
        return equal | (~either_infinite & tol_check)

    OriginalEl autor user2357112

  3. 6

    Esto se hace evidente una vez que usted lea la documentación para cada uno –

    np.isclose

    De los valores de tolerancia son positivos, por lo general, muy pequeñas cantidades. El
    la diferencia relativa (rtol * abs(b)) y la diferencia absoluta
    atol son suman para comparar la diferencia absoluta
    entre a y b.

    matemáticas.isclose

    De los valores a ser considerados cerca, el diferencia entre ellos
    debe ser menor que al menos uno de los límites de tolerancia
    .

    En pocas palabras, la “proximidad” se calcula de forma diferente entre las funciones, de modo que no son para ser usados indistintamente. Como cuestión de qué uso, que depende de su caso de uso. Ambos hacen la misma cosa (aunque np.isclose puede trabajar con matrices, no sólo escalares), pero usted tendrá que ajustar sus valores de tolerancia en consecuencia.

    Otro factor a considerar es que math.isclose fue añadido en python3.5. Así, para el propósito de la compatibilidad con versiones anteriores, puede que desee utilizar la ex.

    OriginalEl autor coldspeed

Dejar respuesta

Please enter your comment!
Please enter your name here