“ ValueError:具有多个元素的数组的真值是不明确的。”使用scipy.integrate.dblquad时

时间:2019-06-11 11:12:35

标签: python numpy scipy

我正在尝试对此功能进行双重集成

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语句中使用 math.isclose 而不是 np.isclose ,则会收到此错误消息,指向同一条语句

  

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

据我了解,布尔数组与这些错误有关,但检查所有内容(包括if语句)都会得到标量布尔值。

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

3 个答案:

答案 0 :(得分:1)

也许这是一个印刷错误。

根据我所做的修改,您看起来就像在打电话:

BaseObserver

实际上您应该打来电话:

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

答案 1 :(得分:0)

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

如何修复它取决于您要实现的目标。假设prob(x,y)返回一个与x / y尺寸相同的numpy数组,其中在条件为true的位置将值替换为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的目的)更有意义。如果要将NaN替换为0.5,则最好测试NaN而不是根据数学条件进行测试:

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

(1)有人可能会争辩说,任何非空数组的求值都应类似于非numpy Python中列表所做的计算,而与值无关(即True的求值为{{1 }})。我很高兴numpy会引发异常,而不是试图猜测这种情况下的情况(可能是np.asarray([False])Trueall或此处的元素需要重写的操作)。

答案 2 :(得分:0)

简短的回答-您需要提供完整的追溯和调用规范。而且您需要正确调用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)都没问题

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)