在this thread中,alko用数字方式计算多元函数的偏导数,发现了一个非凡的答案。
我现在有一个关于增强此函数以接受输入值数组的后续问题。我有一些代码,我循环遍历一大堆n维点,计算每个变量的偏导数,这在计算上非常昂贵。
使用np.vectorize
对相关函数进行矢量化很容易,但它会导致partial_derivative
包装器出现问题:
from scipy.misc import derivative
import numpy as np
def foo(x, y):
return(x**2 + y**3)
def partial_derivative(func, var=0, point=[]):
args = point[:]
def wraps(x):
args[var] = x
return func(*args)
return derivative(wraps, point[var], dx=1e-6)
vfoo = np.vectorize(foo)
>>>foo(3,1)
>>>10
>>>vfoo([3,3], [1,1])
>>>array([10,10])
>>>partial_derivative(foo,0,[3,1])
>>>6.0
>>>partial_derivative(vfoo,0,[[3,3], [1,1]])
>>>TypeError: can only concatenate list (not "float") to list
理想情况下,最后一行应返回[6.0, 6.0]
。在这种情况下,提供给向量化函数vfoo
的两个数组基本上成对压缩,因此([3,3], [1,1])
转换为两个点[3,1]
和[3,1]
。当它传递给函数wraps
时,这似乎会受到损害。它最终传递给函数derivative
的点是[3,3]
。此外,显然TypeError
被抛出。
有没有人有任何建议或建议?有没有人需要做类似的事情?
有时我认为发布SO就是打破精神障碍所需要的。我想我已经让那些可能感兴趣的人工作了:
vfoo = np.vectorize(foo)
foo(3,1)
X = np.array([3,3])
Y = np.array([1,1])
vfoo(X, Y)
partial_derivative(foo,0,[3,1])
partial_derivative(vfoo,0,[X, Y])
最后一行现在返回array([ 6., 6.])
答案 0 :(得分:0)
我对args [var] = x有一个小问题:这可能会永远改变args [var],并且所有值都已通过引用传递,但是你的更改很小。所以你可能得不到你想要的确切答案。这是一个例子:
In[67]: a = np.arange(9).reshape(3,3)
In[68]: b = a[:]
In[69]: b[0,0]=42
In[70]: a
Out[70]:
array([[42, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]])
你需要通过例如:
来解决它def wraps(x):
tmp = args[var]
args[var] = x
ret= func(*args)
args[var] = tmp
return ret
此外,您可以使用numdifftools。他们似乎知道他们在做什么。这将做所有偏导数:
import numpy as np
import numdifftools as nd
def partial_function(f___,input,pos,value):
tmp = input[pos]
input[pos] = value
ret = f___(*input)
input[pos] = tmp
return ret
def partial_derivative(f,input):
ret = np.empty(len(input))
for i in range(len(input)):
fg = lambda x:partial_function(f,input,i,x)
ret[i] = nd.Derivative(fg)(input[i])
return ret
if __name__ == "__main__":
f = lambda x,y: x*x*x+y*y
input = np.array([1.0,1.0])
print ('partial_derivative of f() at: '+str(input))
print (partial_derivative(f,input))
最后:如果你希望你的函数采用一系列参数,例如:
f = lambda x: x[0]*x[0]*x[0]+x[1]*x[1]
然后用(删除'*')
替换相应的行ret = f___(input)