使用 scipy 集成模块规范化函数时出现问题
A problem with normalizing a function using scipy integrate module
我想在 A 到 B 的范围内标准化一个函数(例如,scipy 的 chi2.pdf)。例如,chi2.pdf 被标准化为它的范围 0到无穷大,它在该区域上的积分是 1。为了做到这一点,我可以计算函数在 A 到 B 上的积分,然后将函数除以该积分。我可以用下面的代码实现它:
import numpy as np
from scipy.stats import chi2
from scipy.integrate import quad
A = 2
B = 4
df = 3
z = quad(chi2.pdf,A,B,args=(df,A)[0]
Quad 传递参数 df 作为自由度,A 作为 loc - 由于各种原因,我希望我的卡方函数移动 A。现在我有了 z
,我可以定义一个新函数:
def normalized_chi_2(x,df,A,z):
y = chi2.pdf(x,df,A)/z
return(y)
再次快速检查集成:
integral_chi2 = quad(normalized_chi_2,A,B,args=(df,A,z)[0]
print(integral_chi2)
>0.9999999999999999
说明我的目的达到了。但是有两个函数,并且主要计算 Z 相对笨重,所以我想我可以定义一个新函数并计算 Z inside 那个函数。
def normalized_chi_1(x,df,A):
z = quad(chi2.pdf,A,B,args=(df,A))[0]
y = chi2.pdf(x,df,A) / z
return(y)
现在,当我再次进行快速集成时:
integral_chi1 = quad(normalized_chi_1,A,B,args=(df,A))[0]
print(integral_chi1)
>0.42759329552910064
我没有得到 1,我得到的值等于原始的、未规范化的 chi2.pdf(上面的 z)的值。另一个问题是 normalized_chi_1
(接受 df 和 A,并计算它自己的 z)非常非常慢。例如,方法 2,我在函数外部计算 z 并将其传递给下一个函数需要大约 0.07 秒,而方法 1,我在函数内部计算 z 需要大约 7.30 秒。慢一百倍。
quad
可能在幕后运行一个循环,每次调用您的函数时,它都会调用另一个 quad
来计算 z,所有这些都非常费力。为了对此进行测试,我添加了一个简单的 print 语句,其中包含原始函数的计数器。
count = 0
def normalized_chi_1(x,df,A):
global count
z = quad(chi2.pdf,A,B,args=(df,A))[0]
print(f"calculating z {count}th time")
count += 1
y = chi2.pdf(x,df,A) / z
return(y)
我得到的输出是
calculating z 0th time
...
calculating z 227th time
calculating z 228th time
calculating z 229th time
calculating z 230th time
因此,您正在计算 z 的积分约 230
次,这或多或少地解释了 100x
执行时间的增加。
如果你想要一个函数来计算 z 你可以简单地做
from functools import lru_cache
@lru_cache
def get_z(*ars,args):
return quad(*ars,args)[0]
A = 2
B = 4
df = 3
def normalized_chi_1(x,df,A):
z = get_z(chi2.pdf,A,B,args=(df,A))
y = chi2.pdf(x,df,A) / z
return(y)
integral_chi1 = quad(normalized_chi_1,A,B,args=(df,A))[0]
这给了我正确的结果和 0.07 秒的 运行 时间,但我认为简单地在 main 中定义 z 更好。
我想在 A 到 B 的范围内标准化一个函数(例如,scipy 的 chi2.pdf)。例如,chi2.pdf 被标准化为它的范围 0到无穷大,它在该区域上的积分是 1。为了做到这一点,我可以计算函数在 A 到 B 上的积分,然后将函数除以该积分。我可以用下面的代码实现它:
import numpy as np
from scipy.stats import chi2
from scipy.integrate import quad
A = 2
B = 4
df = 3
z = quad(chi2.pdf,A,B,args=(df,A)[0]
Quad 传递参数 df 作为自由度,A 作为 loc - 由于各种原因,我希望我的卡方函数移动 A。现在我有了 z
,我可以定义一个新函数:
def normalized_chi_2(x,df,A,z):
y = chi2.pdf(x,df,A)/z
return(y)
再次快速检查集成:
integral_chi2 = quad(normalized_chi_2,A,B,args=(df,A,z)[0]
print(integral_chi2)
>0.9999999999999999
说明我的目的达到了。但是有两个函数,并且主要计算 Z 相对笨重,所以我想我可以定义一个新函数并计算 Z inside 那个函数。
def normalized_chi_1(x,df,A):
z = quad(chi2.pdf,A,B,args=(df,A))[0]
y = chi2.pdf(x,df,A) / z
return(y)
现在,当我再次进行快速集成时:
integral_chi1 = quad(normalized_chi_1,A,B,args=(df,A))[0]
print(integral_chi1)
>0.42759329552910064
我没有得到 1,我得到的值等于原始的、未规范化的 chi2.pdf(上面的 z)的值。另一个问题是 normalized_chi_1
(接受 df 和 A,并计算它自己的 z)非常非常慢。例如,方法 2,我在函数外部计算 z 并将其传递给下一个函数需要大约 0.07 秒,而方法 1,我在函数内部计算 z 需要大约 7.30 秒。慢一百倍。
quad
可能在幕后运行一个循环,每次调用您的函数时,它都会调用另一个 quad
来计算 z,所有这些都非常费力。为了对此进行测试,我添加了一个简单的 print 语句,其中包含原始函数的计数器。
count = 0
def normalized_chi_1(x,df,A):
global count
z = quad(chi2.pdf,A,B,args=(df,A))[0]
print(f"calculating z {count}th time")
count += 1
y = chi2.pdf(x,df,A) / z
return(y)
我得到的输出是
calculating z 0th time
...
calculating z 227th time
calculating z 228th time
calculating z 229th time
calculating z 230th time
因此,您正在计算 z 的积分约 230
次,这或多或少地解释了 100x
执行时间的增加。
如果你想要一个函数来计算 z 你可以简单地做
from functools import lru_cache
@lru_cache
def get_z(*ars,args):
return quad(*ars,args)[0]
A = 2
B = 4
df = 3
def normalized_chi_1(x,df,A):
z = get_z(chi2.pdf,A,B,args=(df,A))
y = chi2.pdf(x,df,A) / z
return(y)
integral_chi1 = quad(normalized_chi_1,A,B,args=(df,A))[0]
这给了我正确的结果和 0.07 秒的 运行 时间,但我认为简单地在 main 中定义 z 更好。