【问题标题】:creating a new lambda function by integrating通过集成创建一个新的 lambda 函数
【发布时间】:2017-11-08 20:21:12
【问题描述】:

我在 Python 中使用lambda 函数定义了一个现有函数。该函数表示概率分布的 PDF。我想构建另一个代表 CDF 的 lambda 函数单线。

我不希望使用带有 def 关键字的单独函数定义。

以下是我一直在使用的代码部分:

import numpy as np
import scipy.integrate as integrate

#define range
dx=0.01
X  = np.arange(0,13,dx)

#define a piecewise function for the spline
ul = 1.0
f_pdf = lambda x: np.piecewise(x, [x < ul, x >= ul], [x[x<ul],0])
f_cdf = lambda x: integrate.quad(f_pdf,0,x)

#print the function evaluations
print(f_pdf(X))
print(f_cdf(X))

请注意,我最近发现,对于分段定义,我需要在 x&lt;ul 的情况下限制返回数组的范围,例如 x[x&lt;ul],以便它能够正确处理不同大小的数组。

我从最后一个命令得到的错误包括:

    ---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-ff6550e6092c> in <module>()
     13 #print the function evaluations
     14 print(f_pdf(X))
---> 15 print(f_cdf(X))

<ipython-input-4-ff6550e6092c> in <lambda>(x)
      9 ul = 1.0
     10 f_pdf = lambda x: np.piecewise(x, [x < ul, x >= ul], [x[x<ul],0])
---> 11 f_cdf = lambda x: integrate.quad(f_pdf,0,x)
     12 
     13 #print the function evaluations

/path/anaconda3/lib/python3.6/site-packages/scipy/integrate/quadpack.py in quad(func, a, b, args, full_output, epsabs, epsrel, limit, points, weight, wvar, wopts, maxp1, limlst)
    321     if (weight is None):
    322         retval = _quad(func, a, b, args, full_output, epsabs, epsrel, limit,
--> 323                        points)
    324     else:
    325         retval = _quad_weight(func, a, b, args, full_output, epsabs, epsrel,

/path/anaconda3/lib/python3.6/site-packages/scipy/integrate/quadpack.py in _quad(func, a, b, args, full_output, epsabs, epsrel, limit, points)
    370 def _quad(func,a,b,args,full_output,epsabs,epsrel,limit,points):
    371     infbounds = 0
--> 372     if (b != Inf and a != -Inf):
    373         pass   # standard integration
    374     elif (b == Inf and a != -Inf):

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

当我尝试让它返回与集成端点数组对应的值时。我认为函数integrate.quad不适合将数组作为集成端点,但是有没有合适的替代方案?

我正在使用 Python 3.6.1。

【问题讨论】:

    标签: python python-3.x numpy lambda scipy


    【解决方案1】:

    piecewise的第三个参数应该是

    可调用对象、f(x,*args,**kw) 或标量列表

    x[x &lt; ul] 两者都不是。正如所写,即使是单个评估 f_cdf(3) 也因此失败。

    如果在那里使用可调用对象,

    f_pdf = lambda x: np.piecewise(x, [x < ul, x >= ul], [lambda x: x, 0])
    

    评估f_cdf(3) 有效,返回(0.49999999999999994, 5.551115123125782e-16)。您可能只想要这个元组的第一部分,而不是第二部分,这是对集成误差的估计。所以用

    f_cdf = lambda x: integrate.quad(f_pdf, 0, x)[0]
    

    由于quad 不接受数组作为其第三个参数(它必须是浮点数),因此尝试将 X 传递给f_cdf 将失败。解决这个问题的一个懒惰方法是在函数上拍vectorize

    f_cdf = np.vectorize(lambda x: integrate.quad(f_pdf,0,x)[0])
    

    将使使用f_cdf(X) 成为可能。然而,这很慢。

    与可变上限积分

    一种非常快速但不是很准确的方法是使用cumtrapz 方法:

    print(integrate.cumtrapz(f_pdf(X), X))
    

    f_cdf(X) 快得多,但输出有明显的集成错误。

    要获得准确的结果,可以编写一个 for 循环,在从 X[i-1] 到 X[i] 的非常短的时间间隔内与 quad 进行积分并添加结果。然而,这并不容易放在一行lambda 中。

    精度问题

    您的被积函数 f_cdful 处是不连续的,这会损害积分的精度。为提高精度,在积分范围内提供points=[ul]参数。像这样:

    integrate.quad(f_pdf, 0, x)[0] if x < ul else integrate.quad(f_pdf, 0, x, points=[ul])[0]
    

    【讨论】:

    • @6-white-male 在您的第二个非代码行中您的意思是f_pdf(3) 我同意这一点。我很好奇为什么当我给该函数一个 numpy 数组时,它似乎可以像最初编写的那样工作。
    • @6-white-male 您使用np.vectorize 的快捷方式似乎运行良好,但是在上限之后存在数值不稳定,积分应该是恒定的,但是一些函数评估会波动到0.49999997 并且有些有向上波动。我最终尝试了f_cdf = np.vectorize(lambda x: integrate.quad(f_pdf,0,x,epsabs=1e-15,limit=100)[0]),因为我认为更改容差和/或子区间的数量会使答案更加精确。结果略有变化,但我无法获得超过 8 位的精度。
    【解决方案2】:

    请始终提供您的任何错误的完整回溯,以便我们真正知道它在哪里不起作用。

    但是从错误中我已经可以说,当您编写 np.piecewise(x, [x &lt; ul, x &gt;= ul], [x[x&lt;ul],0]) 时,您在阵列上运行的逻辑测试就是问题所在。也就是说,当你写x &lt; ul时,你的意思是x中的所有值都必须是x[i] &lt; ul[i]吗?你的意思是至少有一个值满足这个条件?

    该问题的修复基本上由错误给出:在np.all()np.any() 函数内的数组之间编写任何逻辑测试,例如np.all(x &lt; ul),如果您希望x 中的所有值小于ul 中的值在同一位置。

    【讨论】:

    • 如您所见,尽管您发表了评论,np.piecewise 部分仍按预期工作。你能解释一下我应该如何根据我需要的评估修改np.piecewise 函数的使用吗?任何小于ul 的参数的线性函数,否则为零。
    • 我是从我在这里看到的唯一逻辑测试中猜测的......我对错误的解释仍然存在:_quad 正在尝试将数组的值与Inf 进行比较(通过您传递的参数),这让我认为_quad 旨在与数组一起使用。如果你想评估_quad 的几个值,我认为最简单的方法是循环x 的值并为每个值调用_quad
    猜你喜欢
    • 1970-01-01
    • 2019-11-10
    • 2016-02-14
    • 2014-05-10
    • 2018-01-13
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 2018-01-11
    相关资源
    最近更新 更多