Python 使用scipy计算积分,其中被积函数是参数来自(任意长)列表的乘积
我想用我在维基百科上找到的Flajolet公式解决一般情况下优惠券收集者的问题(每个优惠券的可能性不同)(请参阅)。根据这个公式,我必须计算一个积分,其中被积函数是乘积。我使用scipy.integrad.quad和lambda表示法进行积分。问题是被积函数中的因子数量不是固定的(参数来自列表)。当我尝试乘以被积函数因子时,我得到了一个错误,因为我似乎无法乘以形式表达式。但是如果我没有,我不知道如何得到积分变量x 我找到了整合产品的方法,例如,如果只有两个因素。它似乎不涉及双重整合或类似的东西。有人能帮忙吗(我对这东西很陌生)Python 使用scipy计算积分,其中被积函数是参数来自(任意长)列表的乘积,python,scipy,numerical-integration,Python,Scipy,Numerical Integration,我想用我在维基百科上找到的Flajolet公式解决一般情况下优惠券收集者的问题(每个优惠券的可能性不同)(请参阅)。根据这个公式,我必须计算一个积分,其中被积函数是乘积。我使用scipy.integrad.quad和lambda表示法进行积分。问题是被积函数中的因子数量不是固定的(参数来自列表)。当我尝试乘以被积函数因子时,我得到了一个错误,因为我似乎无法乘以形式表达式。但是如果我没有,我不知道如何得到积分变量x 我找到了整合产品的方法,例如,如果只有两个因素。它似乎不涉及双重整合或类似的东西。
如果使用
args=
将参数传递给quad
,则可以使用任意数量的参数定义积分函数:
def integrand(x, *p_list):
p_list = np.asarray(p_list)
return 1 - np.product(1 - np.exp(-x * p_list)) #don't need to for-loop a product in numpy
result, abserr = quad(integrand, 0, np.inf, args=[1,1,1,1])
print(result, abserr)
>> 2.083333333333334 2.491001112400493e-10
有关更多信息,请参见如果使用
args=
将参数传递给quad
,则可以使用任意数量的参数定义积分函数:
def integrand(x, *p_list):
p_list = np.asarray(p_list)
return 1 - np.product(1 - np.exp(-x * p_list)) #don't need to for-loop a product in numpy
result, abserr = quad(integrand, 0, np.inf, args=[1,1,1,1])
print(result, abserr)
>> 2.083333333333334 2.491001112400493e-10
有关更多信息,请参见感谢您回答这个问题:作为@Mstaino回答的后续内容,您甚至不需要
参数
,因为您可以通过闭包将它们传递到函数中:
def coupon_collector_expected_samples(probs):
"""
Find the expected number of samples before all "coupons" (with a
non-uniform probability mass) are "collected".
Args:
probs (ndarray): probability mass for each unique item
References:
https://en.wikipedia.org/wiki/Coupon_collector%27s_problem
https://www.combinatorics.org/ojs/index.php/eljc/article/view/v20i2p33/pdf
https://stackoverflow.com/questions/54539128/scipy-integrand-is-product
Example:
>>> import numpy as np
>>> import ubelt as ub
>>> # Check EV of samples for a non-uniform distribution
>>> probs = [0.38, 0.05, 0.36, 0.16, 0.05]
>>> ev = coupon_collector_expected_samples(probs)
>>> print('ev = {}'.format(ub.repr2(ev, precision=4)))
ev = 30.6537
>>> # Use general solution on a uniform distribution
>>> probs = np.ones(4) / 4
>>> ev = coupon_collector_expected_samples(probs)
>>> print('ev = {}'.format(ub.repr2(ev, precision=4)))
ev = 8.3333
>>> # Check that this is the same as the solution for the uniform case
>>> import sympy
>>> n = len(probs)
>>> uniform_ev = float(sympy.harmonic(n) * n)
>>> assert np.isclose(ev, uniform_ev)
"""
import numpy as np
from scipy import integrate
probs = np.asarray(probs)
# Philippe Flajolet's generalized expected value integral
def _integrand(t):
return 1 - np.product(1 - np.exp(-probs * t))
ev, abserr = integrate.quad(func=_integrand, a=0, b=np.inf)
return ev
您还可以看到我的实现速度更快:
import timerit
ti = timerit.Timerit(100, bestof=10, verbose=2)
probs = np.random.rand(100)
from scipy import integrate
def orig_method(p_list):
def integrand(x, *p_list):
p_list = np.asarray(p_list)
return 1 - np.product(1 - np.exp(-x * p_list))
result, abserr = integrate.quad(integrand, 0, np.inf, args=p_list)
return result
ti = timerit.Timerit(100, bestof=10, verbose=2)
for timer in ti.reset('orig_implementation'):
with timer:
orig_method(probs)
for timer in ti.reset('my_implementation'):
with timer:
coupon_collector_expected_samples(probs)
# Results:
# Timed orig_implementation for: 100 loops, best of 10
# time per loop: best=7.267 ms, mean=7.954 ± 0.5 ms
# Timed my_implementation for: 100 loops, best of 10
# time per loop: best=5.618 ms, mean=5.648 ± 0.0 ms
感谢您回答这个问题:作为@Mstaino回答的后续内容,您甚至不需要
args
,因为您可以通过闭包将它们传递到函数中:
def coupon_collector_expected_samples(probs):
"""
Find the expected number of samples before all "coupons" (with a
non-uniform probability mass) are "collected".
Args:
probs (ndarray): probability mass for each unique item
References:
https://en.wikipedia.org/wiki/Coupon_collector%27s_problem
https://www.combinatorics.org/ojs/index.php/eljc/article/view/v20i2p33/pdf
https://stackoverflow.com/questions/54539128/scipy-integrand-is-product
Example:
>>> import numpy as np
>>> import ubelt as ub
>>> # Check EV of samples for a non-uniform distribution
>>> probs = [0.38, 0.05, 0.36, 0.16, 0.05]
>>> ev = coupon_collector_expected_samples(probs)
>>> print('ev = {}'.format(ub.repr2(ev, precision=4)))
ev = 30.6537
>>> # Use general solution on a uniform distribution
>>> probs = np.ones(4) / 4
>>> ev = coupon_collector_expected_samples(probs)
>>> print('ev = {}'.format(ub.repr2(ev, precision=4)))
ev = 8.3333
>>> # Check that this is the same as the solution for the uniform case
>>> import sympy
>>> n = len(probs)
>>> uniform_ev = float(sympy.harmonic(n) * n)
>>> assert np.isclose(ev, uniform_ev)
"""
import numpy as np
from scipy import integrate
probs = np.asarray(probs)
# Philippe Flajolet's generalized expected value integral
def _integrand(t):
return 1 - np.product(1 - np.exp(-probs * t))
ev, abserr = integrate.quad(func=_integrand, a=0, b=np.inf)
return ev
您还可以看到我的实现速度更快:
import timerit
ti = timerit.Timerit(100, bestof=10, verbose=2)
probs = np.random.rand(100)
from scipy import integrate
def orig_method(p_list):
def integrand(x, *p_list):
p_list = np.asarray(p_list)
return 1 - np.product(1 - np.exp(-x * p_list))
result, abserr = integrate.quad(integrand, 0, np.inf, args=p_list)
return result
ti = timerit.Timerit(100, bestof=10, verbose=2)
for timer in ti.reset('orig_implementation'):
with timer:
orig_method(probs)
for timer in ti.reset('my_implementation'):
with timer:
coupon_collector_expected_samples(probs)
# Results:
# Timed orig_implementation for: 100 loops, best of 10
# time per loop: best=7.267 ms, mean=7.954 ± 0.5 ms
# Timed my_implementation for: 100 loops, best of 10
# time per loop: best=5.618 ms, mean=5.648 ± 0.0 ms
你到底在问什么?如果你的公式是正确的,或者是否存在一些现成的包来处理任意长度的情况?对不起,我忽略了你的评论(因为我是这个网站的新手)。与此同时,塔诺女士已经回答了我的问题。这个公式来自维基百科(很可能)是正确的。我不知道的是如何编码你到底在问什么?如果你的公式是正确的,或者是否存在一些现成的包来处理任意长度的情况?对不起,我忽略了你的评论(因为我是这个网站的新手)。与此同时,塔诺女士已经回答了我的问题。这个公式来自维基百科(很可能)是正确的。我不知道的是如何编码。非常感谢。我仍然需要在脑海中构思出细节,并对其进行一些处理,但这似乎是可行的!非常感谢。我仍然需要在脑海中构思出细节,并对其进行一些处理,但这似乎是可行的!