2015-07-15 2 views
4

Мне нужно заполнить большой 2D-массив блоками из меньшего 2D-массива, но при этом учитывать меньшее количество строк столбцов, чем ширина блока на краю новой большой 2D-массив. Например, чтобы создать массив справа от массива слева, используя блок 3x3.Заполнить большую матрицу из меньшей матрицы

[[ 1 2 3 4]   [[ 1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4.] 
[ 5 6 7 8] -> [ 1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4.] 
[ 9 10 11 12]]   [ 1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4.] 
         [ 5. 5. 5. 6. 6. 6. 7. 7. 7. 8. 8.] 
         [ 5. 5. 5. 6. 6. 6. 7. 7. 7. 8. 8.] 
         [ 5. 5. 5. 6. 6. 6. 7. 7. 7. 8. 8.] 
         [ 9. 9. 9. 10. 10. 10. 11. 11. 11. 12. 12.]] 

Я реализовал это, как показано ниже, но я ищу более разумный способ сделать это.

# Smaller array 
a=np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]]) 

# The size of the blocks for filling in the matrix 
blockSize = 3 

# The number of columns and rows of the new matrix (b) 
cols = 11 
rows = 7 
b = np.zeros([rows, cols]) 

for i in range(0, rows, blockSize): 
    ii = i/blockSize 
    if i + blockSize < rows: 
     numRows = blockSize 
    else: 
     numRows = rows - i 
    for j in range(0, cols, blockSize): 
     jj= j/blockSize 
     if j + blockSize < cols: 
      numCols = blockSize 
     else: 
      numCols = cols - j 

     b[i:i+numRows,j:j+numCols] = a[ii,jj] 
+0

что вы хотите хорошо знать математические операции: https://en.wikipedia.org/wiki/Kronecker_product и реализован в numpy: см. http://stackoverflow.com/questions/29752319/build-matrix-from-blocks –

ответ

5

Вы могли бы повторить в два этапа; один раз для столбцов, один раз для строк.

a = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]]) 
blockSize = 3 
cols = 11 
rows = 7 

Каждый раз, список числа повторений для каждого элемента вычисляется из blockSize и либо rows или cols (например [3, 3, 3, 2] для столбцов). Это создает массив требуемого размера:

>>> result = a.repeat([blockSize]*(cols//blockSize) + [cols % blockSize], axis=1) 
>>> result = result.repeat([blockSize]*(rows//blockSize) + [rows % blockSize], axis=0) 
>>> result 
array([[ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4], 
     [ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4], 
     [ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4], 
     [ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8], 
     [ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8], 
     [ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8], 
     [ 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12]]) 

В качестве альтернативы можно использовать что-то вроде np.kron для создания блоков каждого элемента, а затем нарежьте массив требуемого размера. Однако это создает сначала массив, который может быть намного больше, чем необходимо (и может быть неэффективным с памятью).

np.kron(a, np.ones((blockSize, blockSize)))[:rows, :cols] 
2

Вы можете использовать np.repeat повторить вашу матрицу затем использовать простую нарезку, чтобы удалить лишние строки и np.delete, чтобы удалить столбец.

Так как более общий способ можно использовать следующую функцию:

>>> def array_crator(arr,new_shape): 
...  repeat_dims=np.divide(new_shape,arr.shape)+1 
...  return np.delete(a.repeat(repeat_dims[1],axis=1).repeat(repeat_dims[0],axis=0),np.s_[new_shape[1]:],1)[:new_shape[0]] 

Демо:

>>> a=np.arange(1,13).reshape(3,4) 
>>> array_crator(a,(7,11)) 
array([[ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4], 
     [ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4], 
     [ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4], 
     [ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8], 
     [ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8], 
     [ 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8], 
     [ 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12]]) 

Другой пример:

>>> a=np.arange(2,22).reshape(4,5) 
>>> a 
array([[ 2, 3, 4, 5, 6], 
     [ 7, 8, 9, 10, 11], 
     [12, 13, 14, 15, 16], 
     [17, 18, 19, 20, 21]]) 
>>> array_crator(a,(7,11)) 
array([[ 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5], 
     [ 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5], 
     [ 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10], 
     [ 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10], 
     [12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15], 
     [12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15], 
     [17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20]]) 
>>> array_crator(a,(9,17)) 
array([[ 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6], 
     [ 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6], 
     [ 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6], 
     [ 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11], 
     [ 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11], 
     [ 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11], 
     [12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16], 
     [12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16], 
     [12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16]]) 
+0

Каждая строка содержит 12 элементов вместо 11 – franciscod

+0

@franciscod Действительно, я пропустил это, спасибо, что напомнил! – Kasramvd

0

Мне нравится @ ответ acjr, но вот альтернативный метод, используя изящные view_as_blocks()

import numpy as np 
import skimage 

a = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]]) 

# Create output array (including columns which will be trimmed later) 
result = np.zeros((9,12)) 

# Make a special view that's addressable by tile index 
# This view can be indexed like so: 
# result_as_tiles[tile_index_y, tile_index_x, within_tile_y, within_tile_x] 
result_as_tiles = skimage.util.view_as_blocks(result, (3,3)) 
assert result_as_tiles.shape == (3,3) + a.shape 

# Now use simple broadcasting to assign each element 
# of your input matrix to an entire tile of the output 
result_as_tiles[:] = a[:, :, np.newaxis, np.newaxis] 

# Finally, slice off the rows/columns you don't need 
trimmed_result = result[:7,:11] 
print trimmed_result 

отпечатки scikit-образа в:

[[ 1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4.] 
[ 1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4.] 
[ 1. 1. 1. 2. 2. 2. 3. 3. 3. 4. 4.] 
[ 5. 5. 5. 6. 6. 6. 7. 7. 7. 8. 8.] 
[ 5. 5. 5. 6. 6. 6. 7. 7. 7. 8. 8.] 
[ 5. 5. 5. 6. 6. 6. 7. 7. 7. 8. 8.] 
[ 9. 9. 9. 10. 10. 10. 11. 11. 11. 12. 12.]] 
Смежные вопросы