2012-03-27 122 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(像我)。