使用Python/Numpy在数组上评估多元函数

4

我知道Python可以快速计算一个实值、单变量函数f(x)在numpy数组xarr = np.array([x0,x1,...xN])上的结果:

f(xarr) = np.array([f(x0), f(x1), ..., f(xN)])

但是,对于多变量函数,这种语法似乎无法正常工作。比如说我有一个实值函数f(x,y),其中x和y是两个实数。那么是否有正确的语法可以在[(0,0), (0,1), (1,0), (1,1)]上计算该函数的值,而避免使用循环(在Python中总是很慢...)?

编辑:下面是涉及到的函数:

我所提到的5元函数如下:

def chisqr(BigOmega, inc, taustar, Q0, U0):
      QU = QandU(nusdata, BigOmega, inc, taustar, Q0, U0)
      Q = QU[:,0]
      U = QU[:,1]
      return 1./(2.*N) * (np.sum(((Q - Qs)/errQs)**2.) + np.sum(((U - Us)/errUs)**2.))

这里有一个函数调用,其中nusdata、Qs Us是在函数调用之前定义的数组。该函数调用以下函数:

def QandU(nu, BigOmega, inc, taustar, Q0, U0):
      lambdalong = nu+omega-np.pi/2.
      tau3 = taustar * ((1+ecc*np.cos(nu))/(1-ecc**2.))**gamma
      delQ = -tau3 * (1+np.cos(inc)*np.cos(inc))*(np.cos(2.*lambdalong) np.sin(inc)*np.sin(inc))
      delU = -2*tau3*np.cos(inc)*np.sin(2*lambdalong)
      Q = Q0 + delQ*np.cos(BigOmega) - delU * np.sin(BigOmega)
      U = U0 + delQ*np.sin(BigOmega) + delU * np.cos(BigOmega)
      bounds = (inc < 0) or (inc > np.pi/2.) or (BigOmega < -2*np.pi) or (BigOmega > 2*np.pi) or (taustar < 0.) or (taustar > 1.)
      if bounds:
            Q = 10E10
            U = 10E10
      #return U
      return np.column_stack((Q,U))

除了函数参数外,所有变量都在函数外部定义。


2
你能提供你想要评估的函数吗? - syntonym
你只需要定义一个函数来接收一个参数(元组或对),但操作元组的元素。像 f = lambda x: x[0]*x[1] 这样简单的代码就可以工作。 - wflynny
通常有许多种方法可以实现这个,但是没有通用的答案。有些函数很容易实现,而有些则几乎不可能。您需要展示实际的函数来解决问题。 - tom10
感谢您的评论。同义词:我想要评估的函数是一个涉及三角函数等复杂函数的函数,它是由5个参数组成的(实际上是一个chi2)。它不是使用lambda定义的,而是使用简单的def .... return ...语法定义的。我可以把它写下来,但我无法想象这会有什么帮助... - user3310059
嘿,我没有冒犯的意思 - 我会编辑我的回复以包含该函数... - user3310059
1
你能解释一下你想调用的函数和你的问题之间的联系吗?你想在哪个数组上调用哪个函数? - Eric
1个回答

2

举个简单的例子:

def add_squares(x, y):
    return x*x + y*y

xs = np.array([0, 0, 1, 1])
ys = np.array([0, 1, 1, 0])

res = add_squares(x, y)

np.array([0, 1, 2, 1])

你声称 f(xarr) = np.array([f(x0), f(x1), ..., f(xN)]) 并不是普遍适用的。这完全取决于 f 的定义。如果 f 只包含算术运算,则为真,但通常情况下则不是。


你的 QandU 函数应该基本上可以正常工作:

def QandU(nu, BigOmega, inc, taustar, Q0, U0):
    # left unchanged
    lambdalong = nu+omega-np.pi/2.
    tau3 = taustar * ((1+ecc*np.cos(nu))/(1-ecc**2.))**gamma
    delQ = -tau3 * (1+np.cos(inc)*np.cos(inc))*(np.cos(2.*lambdalong) np.sin(inc)*np.sin(inc))
    delU = -2*tau3*np.cos(inc)*np.sin(2*lambdalong)
    Q = Q0 + delQ*np.cos(BigOmega) - delU * np.sin(BigOmega)
    U = U0 + delQ*np.sin(BigOmega) + delU * np.cos(BigOmega)

    # or doesn't vectorize, use bitwise or
    bounds = (inc < 0) | (inc > np.pi/2.) | (BigOmega < -2*np.pi) | (BigOmega > 2*np.pi) | (taustar < 0.) | (taustar > 1.)

    # if statements also don't vectorize
    Q[bounds] = 10E10
    U[bounds] = 10E10

    # stacking is more trouble that it's worth
    return Q, U

你的chisqr函数可能需要传递一个axis=参数给sum,具体取决于你想要对哪些维度进行求和。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接