点积的递归应用

时间:2016-12-15 17:02:27

标签: python numpy recursion

我想在一般情况下应用一个能产生结果的函数:

np.dot(np.dot(np.dot(D3, theta2), D2), theta1)

也就是说,不是指定D3theta2等,而是在一般情况下完成,例如

if n==1:
   answer = np.dot(params['D'+str(n)], params['theta'+str(n - 1)])
else:
   answer = ? 

您对我如何做到这一点有什么想法吗?

4 个答案:

答案 0 :(得分:2)

就像@wwii已经提到的那样,你可以使用functools.reduce代替递归:

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])

答案 1 :(得分:1)

将您的东西放在容器中并使用functools.reduce

答案 2 :(得分:1)

使用functools.reduce提议的优秀解决方案的另一种解决方案是使用numpy' einsum

注意:这不是一个更好的解决方案,只是一种替代方法(而且很有趣)。

例如,对于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)

然后叫它:

>>> np.allclose(recdot(a, b, c), a.dot(b).dot(c)) # True

注2:它有一个限制,只能在26个矩阵中运行(上面字母表中的字母数)。

或者,如果您有一个包含输入矩阵的数组,请更改为:

def recdot(*args):  ->   def recdot(args):

>>> recdot([a,b,c])

答案 3 :(得分:1)

你真正想要的是np.linalg.multi_dot

np.linalg.multi_dot([D3, theta2, D2, theta1])

这具有非常大的优势,即优化收缩顺序是最有效的,而不是简单地在列表中运行。如果你的矩阵是正方形,则没有区别;但是,如果不是这样,这可能是非常有益的。