2012-03-27 121 views
8

简而言之:我有两个矩阵(或阵列):添加不同尺寸/形移位NumPy的矩阵

import numpy 

block_1 = numpy.matrix([[ 0, 0, 0, 0, 0], 
         [ 0, 0, 0, 0, 0], 
         [ 0, 0, 0, 0, 0], 
         [ 0, 0, 0, 0, 0]]) 

block_2 = numpy.matrix([[ 1, 1, 1], 
         [ 1, 1, 1], 
         [ 1, 1, 1], 
         [ 1, 1, 1]]) 

我的block_2block_1元件的位移坐标系。

pos = (1,1) 

我希望能够加入他们(快),可以得到:

[[0 0 0 0 0] 
[0 1 1 1 0] 
[0 1 1 1 0] 
[0 1 1 1 0]] 

在长:我想一个快速的方法来添加两个不同形状的矩阵合在一起,的其中一个矩阵可以被移动。生成的矩阵必须具有第一个矩阵的形状,并将两个矩阵之间的重叠元素相加。如果没有重叠,只是第一个矩阵返回unmutated。

我有正常工作的功能,但它是一种丑陋,按元素:

def add_blocks(block_1, block_2, pos): 
    for i in xrange(0, block_2.shape[0]): 
     for j in xrange(0, block_2.shape[1]): 
      if (i + pos[1] >= 0) and (i + pos[1] < block_1.shape[0]) 
       and (j + pos[0] >= 0) and (j + pos[0] < block_1.shape[1]): 
       block_1[pos[1] + i, pos[0] + j] += block_2[i,j] 
    return block_1 

可以播放或者是切片做到这一点?

我觉得我可能失去了一些明显的东西。

回答

3

您只需找到重叠范围,然后使用切片添加数组。

b1 = np.zeros((4,5)) 
b2 = np.ones((4,3)) 
pos_v, pos_h = 2, 3 # offset 
v_range1 = slice(max(0, pos_v), max(min(pos_v + b2.shape[0], b1.shape[0]), 0)) 
h_range1 = slice(max(0, pos_h), max(min(pos_h + b2.shape[1], b1.shape[1]), 0)) 

v_range2 = slice(max(0, -pos_v), min(-pos_v + b1.shape[0], b2.shape[0])) 
h_range2 = slice(max(0, -pos_h), min(-pos_h + b1.shape[1], b2.shape[1])) 

b1[v_range1, h_range1] += b2[v_range2, h_range2] 

他们就地添加,但你也可以创建一个新的阵列。不过,我可能错过了一些角落案例,但它似乎工作正常。

+0

我最终做了一些非常相似的事情。创建切片对象的能力非常好,谢谢! – fraxel 2012-03-27 12:06:16

+0

我认为v_range1和h_range1代码缺少最终结束')'。 – 2012-03-28 15:03:02

+0

谢谢!我只是修正了这一点。 – jorgeca 2012-03-28 17:58:39

1

我敢肯定有一个快速的NumPy的方式做到这一点,但有一个更有效的方式来做到这一点,即使在正常的Python:

block_1 = [ [ 0, 0, 0, 0, 0], 
      [ 0, 0, 0, 0, 0], 
      [ 0, 0, 0, 0, 0], 
      [ 0, 0, 0, 0, 0]] 

block_2 = [ [ 1, 1, 1], 
      [ 1, 1, 1], 
      [ 1, 1, 1], 
      [ 1, 1, 1]] 

pos = (1, 1) 

x, y = pos 

# width of the rows in block_2 
length = len(block_2[0]) 

# skip the first y rows 
for row_1, row_2 in zip(block_1[y:], block_2): 
    # set length elements offset by x to the sum. 
    row_1[x:length + x] = map(sum, zip(row_2, row_1[x:length + x])) 

print '\n'.join(' '.join(map(str, row)) for row in block_1) 

""" 
0 0 0 0 0 
0 1 1 1 0 
0 1 1 1 0 
0 1 1 1 0 
""" 
12

一个简单的解决方案,它看起来像MATLAB的解决方案是:

import numpy as np 

block_1 = np.zeros((5,4)) #sample data 1 
block_2 = np.ones((4,3)) #sample data 2 

block_1[1:5,1:4] = block_1[1:5,1:4] + block_2 
print(block_1) 

所以打包为一个可重复使用的功能:

import numpy as np 

#Usage: 
# addAtPos(xycoor) 
# - mat1 : matrix to be added 
# - mat2 : add this matrix to mat1 
# - xycoor: tuple (x,y) containing coordinates 
def addAtPos(mat1, mat2, xycoor): 
    size_x, size_y = np.shape(mat2) 
    coor_x, coor_y = xycoor 
    end_x, end_y = (coor_x + size_x), (coor_y + size_y) 
    mat1[coor_x:end_x, coor_y:end_y] = mat1[coor_x:end_x, coor_y:end_y] + mat2 
    return mat1 

block_1 = np.zeros((5,4)) 
block_2 = np.ones((3,3)) 
pos  = (1,1) 

#print result 
print(addAtPos(block_1, block_2, pos)) 
+0

这看起来不错,而且更具可读性。但是,如果某些“block_2”落在“block_1”之外,则会失败。当然容易修复。 – fraxel 2012-03-27 09:45:59

+0

@fraxel是的,你可以随时添加大小检查,如果需要;) – EwyynTomato 2012-03-27 09:52:32

1

这是伟大的,这里是如何通过添加几行jorgeca代码扩展除了3D矩阵:

import numpy as np 

#two 3d arrays, of different size. 
b1 = np.zeros((5,5,5), dtype=np.int) # a 5x5x5 matrix of zeroes 
b2 = np.ones((3,3,3), dtype=np.int) # a 3x3x3 matrix of ones 

pos_v, pos_h, pos_z = 2, 2, 2 # a 3d offset -> to plonk b2 in the corner of b1 

v_range1 = slice(max(0, pos_v), max(min(pos_v + b2.shape[0], b1.shape[0]), 0)) 
h_range1 = slice(max(0, pos_h), max(min(pos_h + b2.shape[1], b1.shape[1]), 0)) 
z_range1 = slice(max(0, pos_z), max(min(pos_z + b2.shape[2], b1.shape[2]), 0)) 

v_range2 = slice(max(0, -pos_v), min(-pos_v + b1.shape[0], b2.shape[0])) 
h_range2 = slice(max(0, -pos_h), min(-pos_h + b1.shape[1], b2.shape[1])) 
z_range2 = slice(max(0, -pos_z), min(-pos_z + b1.shape[2], b2.shape[2])) 

b1[v_range1, h_range1, z_range1] += b2[v_range2, h_range2, z_range2] 

这可能帮助别人谁愿意做相同的3D(像我)。