Numpy: BUG:numpy.percentile输出未排序

创建于 2019-10-12  ·  16评论  ·  资料来源: numpy/numpy

numpy.percentile的输出并不总是排序

再现代码示例:

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()

错误信息:

[True True True True True True True True True True True True True True
真真真真真真真真真真真真真真真
真真真真真真真真真真真真真真真
真真真真真真真真真真真真真真真
真真真真真真真真真真真真真真真
真真真真真真真真真真真真真真真
真真真真真真真真真真真真真真真
真真真真真假假假真真真真假
真真真假]
AssertionError Traceback(最近一次通话)

1 q = np.percentile(np.array([0,1,1,2,2,2,3,4,4,5,5,1,9,9,9,9,8,8,7])* 0.1,np.arange(0,1,0.01)* 100)
2 equals_sorted = np.sort(q)== q
----> 3断言equals_sorted.all()

AssertionError:

Numpy / Python版本信息:

1.17.2 3.6.8(v3.6.8:3c6b436a57,2018年12月24日,02:04:31)
[GCC 4.2.1兼容的Apple LLVM 6.0(clang-600.0.57)]

00 - Bug numpy.lib good first issue

最有用的评论

嘿,似乎已经对@ eric-wieser提供的stackexchange答案之一进行了更新,并提供了很好的替代插值方法。
该线程包括一个单调性证明,并且所提出的修复程序似乎可以解决所有提到的问题。
如果这对于该问题有意义,那么我将愿意将其作为第一次提交来实施,否则其他人可以尝试一下。
20191209_020250

所有16条评论

您为什么希望将其排序? 百分位数是逐元素的-输出按输入顺序排列。

嗨!
确实,百分位数是Elmenet明智的选择-在考虑q ,在我们的案例中是
np.arange(0, 1, 0.01) * 100
我希望对输出进行排序,因为q已排序。

单个ULP中存在一些数字误差,这些误差对于具有相同输出值的不同输入会有所不同。 我怀疑对此有什么可做的。

稍微减少了失败的情况:

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])

这里显示通过差异的非排序。

我认为我们可能对此可以采取一些措施。 我认为这取决于这些行的稳定性,它们执行lerp操作(本质上是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

在线性插值浮点值时,需要进行很多折衷,但是我怀疑这里有一个“正确”的选择,而我们还没有做到。

此处提供更多背景信息: https :

是的,我同意,+ 1是对操作进行重组,以使其严格单调(数字方式)。 如果它也不会更糟,或者至少是几乎相同的精度,那会很好。 我确信我们真的不必担心这里的一些额外操作/速度。

编辑:标记为良好的第一期。 但是在那之后,这可能是python代码中相当直接的重组。

我会对处理这个问题感兴趣。 我正在查看一些失败的案例,并注意到它们都涉及在相同数字之间进行线性插值。 例如,在埃里克(Eric)的示例中,他列出的所有百分位都位于两个9之间。 因此,我认为它们之间的线性插值一定是9完全正确吗? 解决在两个相同的数字之间线性插值的问题似乎可以解决此bug中提出的问题,并且不会对性能造成明显的影响。 但是,如果我们要确保线性插值始终是单调的,则可以这样做,但它需要一个分段函数,我认为这会降低性能。

@ ngonzo95应该有一种方法可以不同地拼写插值算法以实现此目的,即更改/重新排列用于计算的公式(以使其在数学上相同,但在数值上保证单调性)。 无需分段计算。

无需分段计算。

这取决于您对lerp要求。 一些我们可能会或可能不会在乎的:

  • 单调( (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

哦,好吧,我没想到分段是必要的,但是我猜想还不够了解这种内在性。

对其进行更多研究,我发现函数a +(ba)* t具有单调(上述定义)和一致(lerp(a,a,t)= a)的性质。 我认为这应该足以满足功能要求。 似乎此函数的主要缺点之一是lerp(a,b,1)!= b。 但是我认为我们计算权重的方式可以确保0 <= t <1。

似乎此函数的主要缺点之一是lerp(a,b,1)!= b。 但是我认为我们计算权重的方式可以确保0 <= t <1。

请注意,不幸的是,该公式可能会导致lerp(a, b. 1-eps) > b)

开源的新手。
想要解决这个问题,这是我的第一个好问题。 我该如何捐款? 有任何先决条件吗?

我查看了一些失败的案例,发现它们都涉及在相同数字之间进行线性插值

在scikit-learn中,我们最近在这个问题上迷失了方向: https

由于我们期望q严格增加,因此我们可以应用np.maximum.accumulate对数组重新排序。 但是,如果我们可以直接在NumPy中解决问题,那就太好了。 我们可以挖掘任何地方进行修复吗?

@glemaitre :numpy中的所有相关行都在我上面的评论中链接:https: //github.com/numpy/numpy/issues/14685#issuecomment -541467915

嘿,似乎已经对@ eric-wieser提供的stackexchange答案之一进行了更新,并提供了很好的替代插值方法。
该线程包括一个单调性证明,并且所提出的修复程序似乎可以解决所有提到的问题。
如果这对于该问题有意义,那么我将愿意将其作为第一次提交来实施,否则其他人可以尝试一下。
20191209_020250

请注意, quantile() lerp还有另一个问题:无法正确处理inf值,请参阅#12282。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

astrofrog picture astrofrog  ·  4评论

toddrjen picture toddrjen  ·  4评论

qualiaa picture qualiaa  ·  3评论

Kreol64 picture Kreol64  ·  3评论

amuresan picture amuresan  ·  4评论