Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 对数伽马函数的快速算法_Python_Performance_Math_Scipy_Gamma Function - Fatal编程技术网

Python 对数伽马函数的快速算法

Python 对数伽马函数的快速算法,python,performance,math,scipy,gamma-function,Python,Performance,Math,Scipy,Gamma Function,我正在尝试写一个快速算法来计算。目前,我的实现看起来很幼稚,只需迭代1000万次来计算gamma函数的日志(我也在使用numba优化代码) 我根据实现对代码进行了计时,我的代码实际上慢了100000倍。所以我做了一些非常错误或非常幼稚的事情(可能两者都有)。尽管与scipy相比,我的答案至少正确到小数点后4位以内 我试图阅读实现scipy的gammaln函数的_-ufunc代码,但是我不理解编写_-gammaln函数的cython代码 是否有一种更快、更优化的方法可以计算对数伽马函数?如何理解s

我正在尝试写一个快速算法来计算。目前,我的实现看起来很幼稚,只需迭代1000万次来计算gamma函数的日志(我也在使用numba优化代码)

我根据实现对代码进行了计时,我的代码实际上慢了100000倍。所以我做了一些非常错误或非常幼稚的事情(可能两者都有)。尽管与scipy相比,我的答案至少正确到小数点后4位以内

我试图阅读实现scipy的gammaln函数的_-ufunc代码,但是我不理解编写_-gammaln函数的cython代码


是否有一种更快、更优化的方法可以计算对数伽马函数?如何理解scipy的实现,以便将其与我的实现结合起来?

函数的运行时将随着迭代次数线性扩展(达到一定的恒定开销)。因此,减少迭代次数是加速算法的关键。虽然预先计算谐波是一个聪明的想法,但在截断序列时,它实际上会导致更差的精度;结果表明,仅计算序列的一部分就能获得更高的精度

下面的代码是上面发布的代码的修改版本(尽管使用了
cython
而不是
numba

如下图所示,即使经过100次近似,也能获得近似值

在100次迭代中,其运行时间与scipy.special.gammaln的数量级相同:

%timeit special.gammaln(5)
# 932 ns ± 19 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit gammaln(5, 100)
# 1.25 µs ± 20.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
剩下的问题当然是要使用多少次迭代。函数
log1p(t)
可以扩展为小
t
的泰勒级数(这与大
k
的限制有关)。特别是,

log1p(t) = t - t ** 2 / 2 + ...
这样,对于大的
k
,和的参数变为

t - log1p(t) = t ** 2 / 2 + ...
因此,在
t
中,和的参数为零,直到二阶,如果
t
足够小,则可以忽略不计。换句话说,迭代次数应至少与
z
一样大,最好至少大一个数量级


但是,如果可能的话,我会坚持使用
scipy
经过良好测试的实现。

我尝试了numba的并行模式并使用了大部分矢量化函数,从而获得了大约3倍的性能提升(遗憾的是,numba无法理解
numpy.substract.reduce

时代:

#Your function:
%timeit gammaln(1.5)
48.6 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

#My function:
%timeit gammaln_vec(1.5)
15 ms ± 340 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#scpiy's function
%timeit gammaln_sp(1.5)
1.07 µs ± 18.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

尽管如此,使用scipy的函数还是会让您受益匪浅。如果没有C代码,我不知道如何进一步细分

关于您之前的问题,我想一个将
scipy.special
函数包装到Numba的示例也很有用

示例

只要只涉及简单的数据类型(int、double、double*、…),包装Cython cdef函数就非常简单且可移植。有关如何调用scipy.special函数的文档。实际需要包装函数的函数名位于
scipy.special.cython\u special.\uuuupyx\u capi\uuuu
中。可以用不同的数据类型调用的函数名被破坏了,但是确定正确的函数名非常容易(只需查看数据类型)

在Numba中的用法

#Numba example with loops
import numba as nb
import numpy as np
@nb.njit()
def Test_func(A):
  out=np.empty(A.shape[0])
  for i in range(A.shape[0]):
    out[i]=numba_gammaln(A[i])
  return out
计时

data=np.random.rand(1_000_000)
Test_func(A): 39.1ms
gammaln(A):   39.1ms

当然,您可以轻松地并行化此函数,并优于scipy中的单线程gammaln实现,并且您可以在任何Numba编译函数中高效地调用此函数。

什么是
z
的示例输入?我不知道公式,但这并不意味着人们不能尝试将其矢量化-我们需要知道如何调用函数进行测试。此外,如果我们说的速度比Scipy慢100000倍,请确保使用示例输入来运行它不会花费我们一段时间:)。@roganjosh在我的机器上运行带有参数
1
的函数大约需要50毫秒,所以我想这样做是安全的go@user8408080OkiDoki。你知道输入应该是整数还是数组吗?据我所知,它可以是任意复数(请参阅)。但只有一个数字是很好的答案,在你的例子中,它似乎确实工作得很快!一个愚蠢的问题,我如何获得libc.math库?我已经安装了Cython,但似乎找不到libc.math库。
libc.math
应该默认包括在内。然而,我经常犯这样的错误:为cython includes编写
import
,而不是
cimport
。这可能是问题所在吗?在上面的代码中,
import
cimport
的任何排列似乎都不起作用。。。我可以从libc.math cimport运行
import cython
,但不能从libc.math cimport运行
(这导致语法错误)或从libc.math import运行
(这导致modulenofounderror)我的错误@Till Hoffmann,我是在jupyter笔记本中运行的,没有正确的设置。让它工作起来。非常感谢!
#Your function:
%timeit gammaln(1.5)
48.6 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

#My function:
%timeit gammaln_vec(1.5)
15 ms ± 340 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

#scpiy's function
%timeit gammaln_sp(1.5)
1.07 µs ± 18.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
#slightly modified version of https://github.com/numba/numba/issues/3086
from numba.extending import get_cython_function_address
from numba import vectorize, njit
import ctypes
import numpy as np

_PTR = ctypes.POINTER
_dble = ctypes.c_double
_ptr_dble = _PTR(_dble)

addr = get_cython_function_address("scipy.special.cython_special", "gammaln")
functype = ctypes.CFUNCTYPE(_dble, _dble)
gammaln_float64 = functype(addr)

@njit
def numba_gammaln(x):
  return gammaln_float64(x)
#Numba example with loops
import numba as nb
import numpy as np
@nb.njit()
def Test_func(A):
  out=np.empty(A.shape[0])
  for i in range(A.shape[0]):
    out[i]=numba_gammaln(A[i])
  return out
data=np.random.rand(1_000_000)
Test_func(A): 39.1ms
gammaln(A):   39.1ms