I have to fill a larger 2D array with blocks made from a smaller 2D array but still take into account a smaller amount of rows of columns than the width of the block at the edge of the new big 2D array. For example to create the array on the right from the array on the left using a 3x3 block.
[[ 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.]]
I implemented this as seen below but I'm looking for a smarter way of doing it.
# 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]
You could repeat in two stages; once for the columns, once for the rows.
a = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12]])
blockSize = 3
cols = 11
rows = 7
Each time, a list of the number of repetitions for each element is calculated from blockSize
and either rows
or cols
(e.g. [3, 3, 3, 2]
for the columns). This creates an array of the required size:
>>> 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]])
An alternative would be to use something like np.kron
to create blocks of each element and then slice the array to the required size. However, this creates an array first that may be much larger than needed (and may be inefficient with memory).
np.kron(a, np.ones((blockSize, blockSize)))[:rows, :cols]
You can use np.repeat
to repeat your matrix then use a simple slicing to remove the extra rows and np.delete
to remove the column.
So as a more general way you can use following function :
>>> 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]]
Demo:
>>> 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]])
Another example :
>>> 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]])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With