有人可以解释scipy中超几何分布的奇怪行为吗?

Bjö*_*lex 11 python scipy

我在Mac OS X 10.6.4上运行Python 2.6.5(这不是本机版本,我自己安装)与Scipy 0.8.0.如果我执行以下操作:

>>> from scipy.stats import hypergeom
>>> hypergeom.sf(5,10,2,5)
Run Code Online (Sandbox Code Playgroud)

我得到了IndexError.然后我做:

>>> hypergeom.sf(2,10,2,2)
-4.44....
Run Code Online (Sandbox Code Playgroud)

我怀疑负值是由于浮点精度差.然后我又做了第一个:

>>> hypergeom.sf(5,10,2,5)
0.0
Run Code Online (Sandbox Code Playgroud)

现在它有效!有人可以解释一下吗?你也看到了这种行为吗?

dr *_*bob 3

如果对生存函数的第一次调用位于显然应该为零的范围内,则问题似乎会出现(请参阅我对上一个答案的评论)。例如,对于对 hypergeom.sf(x,M,n,N) 的调用,如果对函数的第一次调用超几何函数是 x > n 的情况,则该函数将失败,此时生存函数将始终为零。

您可以通过以下方式暂时解决此问题:

def new_hypergeom_sf(k, *args, **kwds):
    from scipy.stats import hypergeom
    (M, n, N) = args[0:3]
    try:
        return hypergeom.sf(k, *args, **kwds)
    except Exception as inst:
        if k >= n and type(inst) == IndexError:
            return 0 ## or conversely 1 - hypergeom.cdf(k, *args, **kwds)
        else:
            raise inst
Run Code Online (Sandbox Code Playgroud)

现在,如果您编辑 /usr/share/pyshared/scipy/stats/distributions.py (或等效文件)没有问题,则修复可能位于第 3966 行,其中现在显示:

    place(output,cond,self._sf(*goodargs))
    if output.ndim == 0:
        return output[()]
    return output
Run Code Online (Sandbox Code Playgroud)

但如果你把它改成:

    if output.ndim == 0:
        return output[()]
    place(output,cond,self._sf(*goodargs))
    if output.ndim == 0:
        return output[()]
    return output
Run Code Online (Sandbox Code Playgroud)

现在它可以在没有 IndexError 的情况下工作。基本上,如果输出是零维的,因为它未通过检查,它会尝试调用位置,失败,并且不生成分布。(如果已经创建了先前的分布,则不会发生这种情况,这可能就是为什么在早期测试中没有捕获到这种情况。)请注意, place (在 numpy 的 function_base.py 中定义)将更改数组的元素(尽管我是不确定它是否会改变维度),因此最好在放置后仍然保留 0 暗淡检查。我还没有对此进行全面测试,看看这个更改是否会破坏其他任何内容(并且它适用于所有离散随机变量分布),因此最好进行第一个修复。

它确实打破了它;例如,stats.hypergeom.sf(1,10,2,5) 返回零(而不是 2/9)。

在同一部分中,此修复似乎效果更好:

class rv_discrete(rv_generic):
...
    def sf(self, k, *args, **kwds):
    ...
        if any(cond):
            place(output,cond,self._sf(*goodargs))
        if output.ndim == 0:
            return output[()]
        return output
Run Code Online (Sandbox Code Playgroud)