A saída de numpy.percentile
nem sempre é classificada
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()
[Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro
Verdadeiro Verdadeiro Verdadeiro Verdadeiro Verdadeiro Falso Falso Verdadeiro Verdadeiro Verdadeiro Verdadeiro Falso
Verdadeiro Verdadeiro Verdadeiro Falso]
AssertionError Traceback (última chamada mais recente)
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, faixa np (0, 1, 0,01) * 100)
2 equals_sorted = np.sort (q) == q
----> 3 assert equals_sorted.all ()
AssertionError:
1.17.2 3.6.8 (v3.6.8: 3c6b436a57, 24 de dezembro de 2018, 02:04:31)
[GCC 4.2.1 compatível com Apple LLVM 6.0 (clang-600.0.57)]
Por que você espera que seja classificado? O percentil é elemento a elemento - as saídas estão na ordem das entradas.
Oi !
Na verdade, o percentil é o elemento-sábio - ao considerar q
, que em nosso caso é
np.arange(0, 1, 0.01) * 100
.
Espero que a saída seja classificada porque q
está classificado.
Existem alguns erros numéricos em uma única ULP, que diferem para diferentes entradas com o mesmo valor de saída. Duvido que haja algo a ser feito sobre isso.
Um caso de falha ligeiramente reduzido:
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])
aqui mostrando não-classificação por meio do diff.
Acho que provavelmente há algo que podemos fazer a respeito. Acho que isso se resume à estabilidade dessas linhas, que realizam uma operação lerp
(essencialmente add(v_below*weights_below, v_above*weights_above)
):
Há uma série de compensações a serem feitas ao interpolar linearmente valores de ponto flutuante, mas suspeito que haja uma escolha "correta" aqui, e simplesmente não a fizemos.
Mais algumas informações básicas aqui: https://math.stackexchange.com/questions/907327/accurate-floating-point-linear-interpolation
Sim, concordo, +1 em reorganizar as operações para que sejam estritamente monotônicas (numericamente) Seria bom se também não fosse pior, ou pelo menos quase idêntico em termos de precisão. Tenho certeza de que realmente não precisamos nos preocupar com algumas operações / velocidades extras aqui.
EDIT: Marcado como bom primeiro exemplar. Mas depois disso, esta é provavelmente uma reorganização bastante direta no código python.
Eu estaria interessado em resolver esse problema. Eu estava olhando para alguns dos casos de falha e percebi que todos eles envolviam interpolação linear entre o mesmo número. ou seja, no exemplo de Eric, todos os percentis que ele listou estão localizados entre dois 9s. Portanto eu acho que a interpolação linear entre eles deve ser 9 exatamente correta? corrigir o problema de interpolação linear entre dois números que são iguais parece que resolveria os problemas apresentados neste bug e não causaria um impacto perceptível no desempenho. Se, no entanto, quisermos garantir que a interpolação linear será sempre monotônica, podemos fazer isso, mas exigirá uma função por partes que eu acho que diminuiria o desempenho.
@ ngonzo95 deve haver uma maneira de soletrar a aritmética da interpolação de forma diferente para conseguir isso, ou seja, alterar / reorganizar a fórmula que é usada para o cálculo (de forma que seja matematicamente idêntica, mas garanta numericamente a monotonicidade). Nenhum cálculo por partes deve ser necessário.
Nenhum cálculo por partes deve ser necessário.
Depende de quais são seus requisitos em lerp
. Alguns com os quais podemos ou não nos importar:
(lerp(a, b, t1) - lerp(a, b, t0)) * (b - a) * (t1 - t0) >= 0
)a <= lerp(a, b, t) <= b
)lerp(a, b, t) == lerp(b, a, 1-t)
)( 0 <= t <= 1
)
Tudo bem, eu não esperava que remendos fossem necessários, mas acho que não conheço os intrinsecos disso bem o suficiente.
examinando melhor, descobri que a função a + (ba) * t tem a propriedade de ser monotônica (definição mencionada acima) e consistente (lerp (a, a, t) = a). Eu acredito que isso deve ser suficiente para os requisitos de funções. Parece que uma das principais desvantagens dessa função é que lerp (a, b, 1)! = B. No entanto, acho que a maneira como estamos calculando os pesos garante que 0 <= t <1.
Parece que uma das principais desvantagens dessa função é que lerp (a, b, 1)! = B. No entanto, acho que a maneira como estamos calculando os pesos garante que 0 <= t <1.
Observe que infelizmente lerp(a, b. 1-eps) > b)
é possível com essa formulação.
Novo no código aberto.
Queria resolver isso como meu primeiro bom problema. Como posso contribuir? Existem pré-requisitos?
Eu estava olhando para alguns dos casos de falha e percebi que todos eles envolviam interpolação linear entre o mesmo número
No scikit-learn, recentemente nos deparamos com este problema: https://github.com/scikit-learn/scikit-learn/issues/15733
Como esperamos que q
esteja estritamente aumentando, podemos aplicar np.maximum.accumulate
reordenar o array. No entanto, se pudéssemos resolver o problema no NumPy diretamente, isso seria ótimo. Existe algum lugar onde possamos cavar para ter uma boa solução?
@glemaitre : Todas as linhas relevantes em numpy estão vinculadas em meu comentário acima, https://github.com/numpy/numpy/issues/14685#issuecomment -541467915
Ei, parece ter havido uma atualização para uma das respostas stackexchange fornecidas por @ eric-wieser com uma boa interpolação alternativa.
O thread inclui uma prova de monotonicidade e a correção proposta parece resolver todos os problemas mencionados.
Se isso fizesse sentido para o problema, eu estaria disposto a implementar isso como um primeiro commit, ou outra pessoa poderia tentar.
Observe que há outro problema com lerp em quantile()
: os valores inf não são tratados corretamente, consulte # 12282.
Comentários muito úteis
Ei, parece ter havido uma atualização para uma das respostas stackexchange fornecidas por @ eric-wieser com uma boa interpolação alternativa.
O thread inclui uma prova de monotonicidade e a correção proposta parece resolver todos os problemas mencionados.
Se isso fizesse sentido para o problema, eu estaria disposto a implementar isso como um primeiro commit, ou outra pessoa poderia tentar.