2017-08-01 166 views
0

鉴于两个阵列一个(形状= a, b, c, d, e)和b(形状= a, x, b),我想的bx包括尺寸成一个 ,这样一个新的阵列c导致形状= a, x, b, c, d, e。的b值应均匀分布:numpy的:从一个阵列整合尺寸到另一个

  • c.sum(1) == a
  • b.sum(1) == a.sum(axis=(2, 3, 4)) == c.sum(axis=(1, 3, 4, 5)

是否有这样做,这是一个几行numpy的或者是有必要在所有迭代的任何聪明的办法手动值b[x]

我目前的解决方案:

for a, x, b in zip(*_b_.nonzero()): 
    tot = _a_[a, b].sum() 
    for c, d, e in zip(*_a_[a, b].nonzero()): 
     val = _b_[a, a, b] 
     frac = _a_[a, b, c, d, e]/tot 
     _c_[a, x, b, c, d, e] = val * frac 
+0

'c = a [:,None,...] + b [:,:,:None,None,None]'应该形成一个正确维度的新矩阵。缩放'a'或'b'可能会满足您的总和条件。我还没有研究他们足以说肯定。 – hpaulj

+0

我用一些示例代码更新了描述。我不认为添加_a_和_b_会起作用... – orange

+2

请大家帮忙,不要在维和变量中使用相同的变量名。它使你的代码和描述非常难以阅读。 –

回答

0

这是一种方式,三线要做到这一点,但首先一些关于我的做法的话:

  • 为了更好的符号,我将使用大写字母矩阵和索引的小写字母。所以我们有A[a,b,c,d,e]B[a,x,b]作为输入。
  • 根据您的代码,C对于所有x都是一样的,所以我们并不真的需要该轴进行计算(如果需要,您可以将其添加为新维度并在之后复制条目)。
  • B[a,a,b]可以沿着前两个轴取对角线。
  • tot超过指数c,d,e的总和,我们可以在这个存储在预先计算阵列Tot[a,b]
  • 能在最后一步使用numpy.einsum,我会先采取逆Tot = 1/Tot

这里是完整的代码:

import numpy 

# generate some example input 
a = 2 
b = 3 
c = 4 
d = 5 
e = 6 
x = 7 

A = numpy.arange(a*b*c*d*e).reshape((a,b,c,d,e)) 
B = numpy.arange(a*x*b).reshape((a,x,b)) 
C = numpy.zeros((a,x,b,c,d,e)) 

# solution by orange 
for a, x, b in zip(*B.nonzero()): 
    tot = A[a, b].sum() 
    for c, d, e in zip(*A[a, b].nonzero()): 
     val = B[a, a, b] 
     frac = A[a, b, c, d, e]/tot 
     C[a, x, b, c, d, e] = val * frac 

# new solution 
B2 = numpy.diagonal(B, axis1=0, axis2=1).transpose() # contract B_aab -> B2_ab 
Tot = 1/numpy.sum(A, (2,3,4)) # contract \sum_cde A_abcde -> 1/Tot_ab 
C2 = numpy.einsum('ab,abcde,ab->abcde',B2,A,Tot) 

# compare (should print x times True) 
for i in range(C.shape[1]): 
    C_ = C[:,i,:,:,:] 
    print(numpy.all(numpy.isclose(C_,C2))) 

编辑:如果numpy.einsum()是你太慢了,你可以实现在用Cython与for厕所的最后一步PS。