Python 点积的递归应用
我想应用一个函数,在一般情况下生成结果:Python 点积的递归应用,python,numpy,recursion,Python,Numpy,Recursion,我想应用一个函数,在一般情况下生成结果: np.dot(np.dot(np.dot(D3, theta2), D2), theta1) 也就是说,不是指定D3,theta2等,而是在一般情况下进行,如 if n==1: answer = np.dot(params['D'+str(n)], params['theta'+str(n - 1)]) else: answer = ? 你知道我该怎么做吗?把你的东西放在一个容器里,像@wwii中提到的那样,你可以用它来代替递归: im
np.dot(np.dot(np.dot(D3, theta2), D2), theta1)
也就是说,不是指定D3
,theta2
等,而是在一般情况下进行,如
if n==1:
answer = np.dot(params['D'+str(n)], params['theta'+str(n - 1)])
else:
answer = ?
你知道我该怎么做吗?把你的东西放在一个容器里,像@wwii中提到的那样,你可以用它来代替递归:
import functools
def dot(a, b):
return 'dot({}, {})'.format(a, b)
>>> functools.reduce(dot, ['theta2', 'D2', 'theta1'], 'D3')
'dot(dot(dot(D3, theta2), D2), theta1)'
只需将变量替换为实际函数和变量:
functools.reduce(np.dot, [D3, theta2, D2, theta1])
使用
functools.reduce
提出的优秀解决方案的替代方案是使用numpy
注意:这不是一个更好的解决方案,只是一种替代方法(而且很有趣)
例如,对于3个随机数组:
>>> a = np.random.randn(3,3)
>>> b = np.random.randn(3,3)
>>> c = np.random.randn(3,3)
递归点积可以写成:
>>> result = np.einsum('ij,jk,kl->il', a, b, c)
>>> np.allclose(result, a.dot(b).dot(c)) # True
def recdot(*args):
# Generate the einstring equivalent to all the input matrices
s='abcdefghijklmnopqrstuvwxyz'
einstr = ','.join([s[i:i+2] for i in range(len(args))])
einstr += '->{}{}'.format(s[0],s[len(args)])
return np.einsum(einstr, *args)
然后,可以将通用函数编写为:
>>> result = np.einsum('ij,jk,kl->il', a, b, c)
>>> np.allclose(result, a.dot(b).dot(c)) # True
def recdot(*args):
# Generate the einstring equivalent to all the input matrices
s='abcdefghijklmnopqrstuvwxyz'
einstr = ','.join([s[i:i+2] for i in range(len(args))])
einstr += '->{}{}'.format(s[0],s[len(args)])
return np.einsum(einstr, *args)
然后称之为:
>>> np.allclose(recdot(a, b, c), a.dot(b).dot(c)) # True
注2:它有限制,只能在26个矩阵中操作(上述字母表中的字母数)
或者,如果您有一个包含输入矩阵的数组,请更改为:
def recdot(*args): -> def recdot(args):
及
您真正想要的是
np.linalg.multi\u dot
:
np.linalg.multi_dot([D3, theta2, D2, theta1])
这有一个非常大的优势,即优化收缩顺序以获得最有效的效果,而不是简单地遍历列表。如果你的矩阵是平方的,就没有差别;但是,如果不是这样的话,这是非常有益的。这样做的主要缺点是
np.einsum
会比dot
慢很多。由于einsum
只是简单地在索引上循环,您的示例的刻度为N^4
,而不是N^3
。这将在NumPy 1.12中更改,但需要注意。您确实希望使用np.linalg.multi\u dot
。