2012-03-27 10 views
8

Kurz gesagt: Ich habe zwei Matrizen (oder Arrays):Hinzufügen verschiedene Größe/Form verschoben NumPy Matrizen

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

Ich habe die Verschiebung der block_2 im block_1 Element-Koordinatensystem.

pos = (1,1) 

Ich möchte in der Lage sein, sie (schnell) hinzuzufügen, zu erhalten:

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

In lange: Ich würde eine schnelle Art und Weise wie zwei verschiedene Form hinzufügen Matrizen zusammen, wo eine der Matrizen können verschoben werden. Die resultierende Matrix muss die Form der ersten Matrix haben, und die überlappenden Elemente zwischen den zwei Matrizen werden summiert. Wenn es keine Überlappung gibt, wird nur die erste Matrix unmutiert zurückgegeben.

Ich habe eine Funktion, die in Ordnung, aber es ist irgendwie hässlich, und element funktioniert:

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 

Kann Rundfunk oder Aufschneiden dies vielleicht tun?

Ich fühle mich, als ob ich etwas Offensichtliches vermisse.

Antwort

3

Sie müssen nur den überlappenden Bereich finden und dann die Arrays mit Slicing hinzufügen.

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] 

Sie werden an Ort und Stelle hinzugefügt, aber Sie können auch ein neues Array erstellen. Ich hätte vielleicht einige Eckfälle vermisst, aber es scheint gut zu funktionieren.

+0

Ich habe etwas sehr ähnliches getan. Die Fähigkeit, Slice-Objekte zu erstellen, ist wirklich großartig, danke dafür! – fraxel

+0

Ich denke, die v_range1 und h_range1 Code fehlt ein abschließendes ')'. –

+0

Danke! Ich habe das gerade behoben. – jorgeca

1

Ich bin sicher, es ist ein schneller NumPy Weg, dies zu tun, aber es ist ein effizienter Weg, um es auch im normalen Python zu tun:

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

Eine einfache Lösung, die MATLAB Lösung sieht aus wie ist:

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) 

so verpacken es als wiederverwendbare Funktion:

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

Das sieht gut aus und viel lesbarer. Aber wenn etwas von 'block_2' außerhalb von' block_1' liegt, schlägt es fehl. Leicht zu reparieren natürlich. – fraxel

+0

@fraxel Yeah, du kannst immer eine Größenprüfung bei Bedarf hinzufügen;) – EwyynTomato

1

Das ist großartig, und hier ist, wie die zusätzlich zu einer 3D-Matrix zu erweitern, indem Sie ein paar Zeilen zu jorgeca den Code hinzufügen:

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] 

Dies könnte jemand helfen, die das gleiche in 3d (wie ich tun will).

Verwandte Themen