Numpy: ERROR: la salida de numpy.percentile no está ordenada

Creado en 12 oct. 2019  ·  16Comentarios  ·  Fuente: numpy/numpy

La salida de numpy.percentile no siempre está ordenada

Ejemplo de código de reproducción:

import numpy as np
q = np.arange(0, 1, 0.01) * 100
percentile = np.percentile(np.array([0, 1, 1, 2, 2, 3, 3 , 4, 5, 5, 1, 1, 9, 9 ,9, 8, 8, 7]) * 0.1, q)
equals_sorted = np.sort(percentile) == percentile
print(equals_sorted)
assert equals_sorted.all()

Mensaje de error:

[Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero Verdadero
Verdadero Verdadero Verdadero Verdadero Verdadero Falso Falso Verdadero Verdadero Verdadero Verdadero Falso
Verdadero Verdadero Verdadero Falso]
AssertionError Traceback (última llamada más reciente)
en
1 q = np.percentil (np.array ([0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 1, 1, 9, 9, 9, 8, 8, 7]) * 0,1, np. Rango (0, 1, 0,01) * 100)
2 igual_ordenados = np.ordenar (q) == q
----> 3 afirmar igual_ordenados.todos ()

AssertionError:

Información de la versión de Numpy / Python:

1.17.2 3.6.8 (v3.6.8: 3c6b436a57, 24 de diciembre de 2018, 02:04:31)
[GCC 4.2.1 Compatible con Apple LLVM 6.0 (clang-600.0.57)]

00 - Bug numpy.lib good first issue

Comentario más útil

Oye, parece que se ha actualizado una de las respuestas de stackexchange proporcionadas por @ eric-wieser con una buena interpolación alternativa.
El hilo incluye una prueba de monotonicidad, y la solución propuesta parece abordar todos los problemas mencionados.
Si esto tuviera sentido para el problema, estaría dispuesto a implementar esto como un primer compromiso, o alguien más podría intentarlo.
20191209_020250

Todos 16 comentarios

¿Por qué esperaría que se corrija? El percentil es por elementos: las salidas están en el orden de las entradas.

Hola !
De hecho, el percentil es elmenet - cuando se considera q , que en nuestro caso es
np.arange(0, 1, 0.01) * 100 .
Espero que la salida se ordene porque q está ordenado.

Hay algunos errores numéricos dentro de un solo ULP, que difieren para diferentes entradas con el mismo valor de salida. Dudo que haya algo que se pueda hacer al respecto.

Un caso fallido ligeramente reducido:

In [40]: np.percentile(np.array([0, 1, 1, 2, 2, 3, 3 , 4, 5, 5, 1, 1, 9, 9 ,9, 8, 8, 7]) * 0.1, [89, 90, 95, 96, 98, 99])
Out[40]: array([0.9, 0.9, 0.9, 0.9, 0.9, 0.9])

In [41]: np.diff(_)
Out[41]:
array([-1.11022302e-16,  2.22044605e-16, -1.11022302e-16,  1.11022302e-16,
       -1.11022302e-16])

aquí se muestra la falta de ordenación a través de la diferencia.

Creo que probablemente hay algo que podamos hacer al respecto. Creo que esto se reduce a la estabilidad de estas líneas, que realizan una operación lerp (esencialmente add(v_below*weights_below, v_above*weights_above) ):

https://github.com/numpy/numpy/blob/b9fa88eec62e34e906689408096beb2450830d9a/numpy/lib/function_base.py#L3907 -L3908

https://github.com/numpy/numpy/blob/b9fa88eec62e34e906689408096beb2450830d9a/numpy/lib/function_base.py#L3928 -L3929

https://github.com/numpy/numpy/blob/b9fa88eec62e34e906689408096beb2450830d9a/numpy/lib/function_base.py#L3939 -L3942

Hay un montón de compensaciones al interpolar linealmente valores de punto flotante, pero sospecho que hay una elección "correcta" aquí, y simplemente no la hemos hecho.

Más antecedentes aquí: https://math.stackexchange.com/questions/907327/accurate-floating-point-linear-interpolation

Sí, estoy de acuerdo, +1 en reorganizar las operaciones para que sea estrictamente monótona (numéricamente). Sería bueno si tampoco es peor, o al menos casi idéntica en cuanto a precisión. Estoy seguro de que realmente no tenemos que preocuparnos por algunas operaciones / velocidad adicionales aquí.

EDITAR: Marcado como buen primer número. Pero después de eso, esta es probablemente una reorganización bastante sencilla dentro del código Python.

Me interesaría abordar este tema. Estaba mirando algunos de los casos fallidos y noté que todos involucraban interpolación lineal entre el mismo número. es decir, en el ejemplo de Eric, todos los percentiles que enumeró están ubicados entre dos nueves. Por lo tanto, creo que la interpolación lineal entre ellos debe ser exactamente correcta. arreglar el problema de interpolar linealmente entre dos números que son iguales parece que solucionaría los problemas presentados en este error y no causaría un impacto notable en el rendimiento. Sin embargo, si queremos asegurarnos de que la interpolación lineal sea siempre monótona, podemos hacerlo, pero requerirá una función por partes que creo que disminuiría el rendimiento.

@ ngonzo95 debería haber una forma de escribir la aritmética de la interpolación de manera diferente para lograr esto, es decir, cambiar / reorganizar la fórmula que se usa para el cálculo (de modo que sea matemáticamente idéntica, pero numéricamente garantice la monotonicidad). No debería ser necesario ningún cálculo por partes.

No debería ser necesario ningún cálculo por partes.

Depende de cuáles sean sus requisitos en lerp . Algunos que nos pueden interesar o no:

  • monótono ( (lerp(a, b, t1) - lerp(a, b, t0)) * (b - a) * (t1 - t0) >= 0 )
  • acotado ( a <= lerp(a, b, t) <= b )
  • simétrico ( lerp(a, b, t) == lerp(b, a, 1-t) )

( 0 <= t <= 1 )

Oh, está bien, no esperaba que fuera necesario por partes, pero supongo que no conozco las intrínsecas de esto lo suficientemente bien.

Al investigarlo más, descubrí que la función a + (ba) * t tiene la propiedad de ser tanto monótona (definición mencionada anteriormente) como consistente (lerp (a, a, t) = a). Creo que esto debería ser suficiente para los requisitos de funciones. Parece que uno de los principales inconvenientes de esta función es que lerp (a, b, 1)! = B. Sin embargo, creo que la forma en que calculamos los pesos asegura que 0 <= t <1.

Parece que uno de los principales inconvenientes de esta función es que lerp (a, b, 1)! = B. Sin embargo, creo que la forma en que calculamos los pesos asegura que 0 <= t <1.

Tenga en cuenta que, lamentablemente, lerp(a, b. 1-eps) > b) es posible con esa formulación.

Nuevo en el código abierto.
Quería resolver esto como mi buen primer problema. ¿Cómo puedo contribuir? ¿Existe algún requisito previo?

Estaba mirando algunos de los casos fallidos y noté que todos involucraban interpolación lineal entre el mismo número

En scikit-learn, recientemente nos topamos con este problema: https://github.com/scikit-learn/scikit-learn/issues/15733

Como esperamos que q aumente estrictamente, podemos aplicar np.maximum.accumulate reordenar la matriz. Sin embargo, si pudiéramos resolver el problema directamente en NumPy, sería genial. ¿Hay algún lugar donde podamos profundizar para tener una buena solución?

@glemaitre : Todas las líneas relevantes en numpy están vinculadas en mi comentario anterior, https://github.com/numpy/numpy/issues/14685#issuecomment -541467915

Oye, parece que se ha actualizado una de las respuestas de stackexchange proporcionadas por @ eric-wieser con una buena interpolación alternativa.
El hilo incluye una prueba de monotonicidad, y la solución propuesta parece abordar todos los problemas mencionados.
Si esto tuviera sentido para el problema, estaría dispuesto a implementar esto como un primer compromiso, o alguien más podría intentarlo.
20191209_020250

Tenga en cuenta que hay otro problema con lerp en quantile() : los valores inf no se manejan correctamente, vea # 12282.

¿Fue útil esta página
0 / 5 - 0 calificaciones