【问题标题】:"ValueError: The truth value of an array with more than one element is ambiguous." when using scipy.integrate.dblquad“ValueError:具有多个元素的数组的真值不明确。”使用 scipy.integrate.dblquad 时
【发布时间】:2019-06-11 23:14:05
【问题描述】:

我正在尝试对此函数执行双重积分

def prob(x,y):
    ch = np.sqrt((3-y)**2 + x**2)
    hb = np.sqrt((4-x)**2 + y**2)
    if np.isclose(4 * y, 12 - 3 * x):
        # Without the if statement, any x, y values that satisfy the condition will return nan
        return 0.5
    else:
        return (np.arccos((ch**2 + hb**2 - 25) / (2 * ch * hb)))/(2*np.pi)

Contour plot of the function

from scipy import integrate as integ
integ.dblquad(prob(x,y), 0, 4, lambda x: 0, lambda x: 3)

但是我得到了这个指向 if 语句的错误消息

ValueError:具有多个元素的数组的真值不明确。使用 a.any() 或 a.all()

简单地说,如果我在 if 语句中使用 ma​​th.isclose 而不是 np.isclose,我会收到指向同一语句的错误消息

TypeError:只有 size-1 的数组可以转换为 Python 标量

据我了解,布尔数组与这些错误有关,但检查包括 if 语句在内的所有内容会产生一个标量布尔值。

那么有什么办法可以解决这个问题吗?

【问题讨论】:

标签: python numpy scipy


【解决方案1】:

也许这是一个印刷错误。

从我所做的编辑看来,你在打电话:

integ.dblquad(prob(x, y), 0, 4, lambda x: 0, lambda x: 3)

事实上你应该打电话:

integ.dblquad(prob, 0, 4, lambda x: 0, lambda x: 3)

我相信您可能有数组x 和数组y 在第一种方式调用dblquad 时导致错误。

例如

x = np.array([1,2,3])
y = np.array([3,4,5])
integ.dblquad(prob(x, y), 0, 4, lambda x: 0, lambda x: 3)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

integ.dblquad(prob, 0, 4, lambda x: 0, lambda x: 3)
(4.42854383700761, 1.8525461432365937e-08)

【讨论】:

  • 我已回滚您的编辑。请不要编辑问题中的代码,尤其是以使整个问题无效的方式。您可以随时投票关闭作为拼写错误。
  • 哦,我犯了一个高中生的错误,我不知道。感谢您指出。我忘了它应该是没有(x,y)的概率
【解决方案2】:

嗯,您得到的错误对诊断很有帮助。问题是np.isclose 将返回一个布尔数组,并且试图将这样的数组强制转换为单个值(if 子句会这样做)会引发错误。 (1)

如何解决它更多地取决于您想要实现的目标。假设prob(x,y) 应该返回一个与 x/y 维度相同的 numpy 数组,其中在条件为真的位置将值替换为 0.5,您可以使用:

output = (np.arccos((ch**2 + hb**2 - 25) / (2 * ch * hb)))/(2*np.pi)
output[np.isclose(4 * y, 12 - 3 * x)] = .5
return output

请注意,这可能不是解决您的实际问题的最佳方法。将 NaN 保持在计算失败的位置通常更有意义(这就是 NaN 的用途)。如果你想用 0.5 替换 NaN,你最好测试 NaN 而不是你的数学条件:

output = (np.arccos((ch**2 + hb**2 - 25) / (2 * ch * hb)))/(2*np.pi)
output[np.isnan(output)] = .5
return output

(1) 有人可能会争辩说,任何非空数组都应该评估为 True,类似于非 numpy Python 中的列表,并且不管值如何(即 np.asarray([False]) 评估为 True)。我很高兴 numpy 会引发异常,而不是试图猜测在那种情况下我想要什么(可能是allanylen(array)>0,或者在这里需要重写的元素操作)。

【讨论】:

  • 我在想类似的事情,但真正的问题是@Grrr 修改了问题中的代码,使其无法回答。
【解决方案3】:

简短回答 - 您需要提供完整的回溯和调用规范。并且你需要正确调用dblquad

===

当你打电话时x,y是什么

integ.dblquad(prob(x,y), 0, 4, lambda x: 0, lambda x: 3)

根据这两个变量,错误可能会在 dblquad 被调用之前上升。

dblquad 的第一个参数应该是一个函数,而不是一个数组。使用 prob 而不是 prob(x,y) 可能会起作用。

给定 2 个标量 prob 有效:

In [674]: prob(1,2)                                                                                    
Out[674]: 0.4685835209054995

给定两个数组,我们得到了歧义错误:

In [675]: prob(np.arange(3),np.arange(1,4))                                                            
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-675-4b16a88f567e> in <module>
----> 1 prob(np.arange(3),np.arange(1,4))

<ipython-input-673-e31785dd54a5> in prob(x, y)
      2     ch = np.sqrt((3-y)**2 + x**2)
      3     hb = np.sqrt((4-x)**2 + y**2)
----> 4     if np.isclose(4 * y, 12 - 3 * x):
      5         # Without the if statement, any x, y values that satisfy the condition will return nan
      6         return 0.5

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

完整的回溯(您应该给我们)显示问题出在isclose 调用上:

In [676]: np.isclose(np.arange(3),np.arange(1,4))                                                      
Out[676]: array([False, False, False])

它产生一个布尔数组,不能在if 子句中使用。

使用math.isclose 会引发错误,因为math 函数只接受标量。它们不适用于数组(多值数组)。

正确使用dblquad,它可以工作:

In [678]: integ.dblquad(prob, 0,4,lambda x:0, lambda x:3)                                              
Out[678]: (4.42854383700761, 1.8525461432365937e-08)

dblquad 将标量值传递给您的函数,因此使用 isclose(numpy 或数学)没有问题

使用带有标量输入的math 函数更快:

def probm(x,y):
    ch = math.sqrt((3-y)**2 + x**2)
    hb = math.sqrt((4-x)**2 + y**2)
    if math.isclose(4 * y, 12 - 3 * x):
        # Without the if statement, any x, y values that satisfy the condition will return nan
        return 0.5
    else:
        return (math.acos((ch**2 + hb**2 - 25) / (2 * ch * hb)))/(2*math.pi)

In [683]: integ.dblquad(probm, 0,4,lambda x:0, lambda x:3)                                             
Out[683]: (4.428543836134556, 1.8890715880459652e-08)

更快:

In [685]: timeit integ.dblquad(prob, 0,4,lambda x:0, lambda x:3)                                       
11.7 s ± 24.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [686]: timeit integ.dblquad(probm, 0,4,lambda x:0, lambda x:3)                                      
272 ms ± 1.12 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 2020-05-12
    • 2016-01-26
    相关资源
    最近更新 更多