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