3
arr = [[1 0 0]    # 3x3
       [0 1 0]
       [0 0 1]]

largeArr = [[1 1 0 0 0 0]   # 6x6
            [1 1 0 0 0 0]
            [0 0 1 1 0 0]
            [0 0 1 1 0 0]
            [0 0 0 0 1 1]
            [0 0 0 0 1 1]]

Like above, I want to retain the same 'grid' format whilst increasing the dimensions of the 2D array. How would I go about doing this? I assume the original matrix can only be scaled up by an integer n.

Ali_Sh
  • 2,667
  • 3
  • 43
  • 66
Wulfgar
  • 35
  • 4

4 Answers4

1

You can use repeat() twice:

arr.repeat(2, 0).repeat(2, 1)

This outputs:

[[1. 1. 0. 0. 0. 0.]
 [1. 1. 0. 0. 0. 0.]
 [0. 0. 1. 1. 0. 0.]
 [0. 0. 1. 1. 0. 0.]
 [0. 0. 0. 0. 1. 1.]
 [0. 0. 0. 0. 1. 1.]]
BrokenBenchmark
  • 18,126
  • 7
  • 21
  • 33
1

You could use scipy.ndimage.zoom

In [3]: arr = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])

In [4]: ndimage.zoom(arr, 2, order=0, grid_mode=True, mode="nearest")
Out[4]: 
array([[1, 1, 0, 0, 0, 0],
       [1, 1, 0, 0, 0, 0],
       [0, 0, 1, 1, 0, 0],
       [0, 0, 1, 1, 0, 0],
       [0, 0, 0, 0, 1, 1],
       [0, 0, 0, 0, 1, 1]])
fabda01
  • 3,384
  • 2
  • 31
  • 37
  • Interesting. Could handle where `1` could be on other indices than the matrix diagonal e.g. `arr = np.array([[1, 0, 0], [0, 0, 1], [0, 0, 1]])`? – Ali_Sh Jun 27 '22 at 08:47
  • 1
    @Ali_Sh Good point. scipy.ndimage.zoom calculates the value of the elements in the grid using spline interpolation of the elements of the input array. By default it uses `order=3`, which will calculate the value of the elements based on the cubic interpolation of the neighboring elements. However, this effect is undesirable in this question, and you can avoid it by using `order=0`, which will simply interpolate the value of the destination element based on the nearest element. I updated my answer for this use case. – fabda01 Jun 27 '22 at 09:53
  • I am getting problem yet for the example that I wrote in the comment above (index --> `[1, 1]` must be equal to `1` not `0`). And how can we specify how many times each value must be repeated e.g. if we need a `3*3` matrix for each value (it seems you must specify `zoom` in your answer as your previous edit i.e. `ndimage.zoom(arr, n, order=0, grid_mode=True, mode="nearest")`). – Ali_Sh Jun 27 '22 at 10:53
  • I don't know why, it works on Colab (SciPy is updated) correctly, but on my machine (SciPy is not updated to the latest version) it get wrong result. – Ali_Sh Jun 27 '22 at 12:03
1

You can use numba if performance is of importance (similar post) with no python jitting and in parallel mode if needed (this code can be written faster by some optimizations):

@nb.njit      # @nb.njit("int64[:, ::1](int64[:, ::1], int64)", parallel =True)
def numba_(arr, n):
    res = np.empty((arr.shape[0] * n, arr.shape[0] * n), dtype=np.int64)
    for i in range(arr.shape[0]):     # for i in nb.prange(arr.shape[0])
        for j in range(arr.shape[0]):
            res[n * i: n * (i + 1), n * j: n * (j + 1)] = arr[i, j]
    return res

So, as an example:

arr = [[0 0 0 1 1]
       [0 1 1 1 1]
       [1 1 0 0 1]
       [0 0 1 0 1]
       [0 1 1 0 1]]

res (n=3):
[[0 0 0 0 0 0 0 0 0 1 1 1 1 1 1]
 [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1]
 [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1]
 [0 0 0 1 1 1 1 1 1 1 1 1 1 1 1]
 [0 0 0 1 1 1 1 1 1 1 1 1 1 1 1]
 [0 0 0 1 1 1 1 1 1 1 1 1 1 1 1]
 [1 1 1 1 1 1 0 0 0 0 0 0 1 1 1]
 [1 1 1 1 1 1 0 0 0 0 0 0 1 1 1]
 [1 1 1 1 1 1 0 0 0 0 0 0 1 1 1]
 [0 0 0 0 0 0 1 1 1 0 0 0 1 1 1]
 [0 0 0 0 0 0 1 1 1 0 0 0 1 1 1]
 [0 0 0 0 0 0 1 1 1 0 0 0 1 1 1]
 [0 0 0 1 1 1 1 1 1 0 0 0 1 1 1]
 [0 0 0 1 1 1 1 1 1 0 0 0 1 1 1]
 [0 0 0 1 1 1 1 1 1 0 0 0 1 1 1]]

Performances (perfplot)

In my benchmarks, numba will be the fastest (for large n, parallel mode will be better), after that BrokenBenchmark answer will be faster than scipy.ndimage.zoom. In the benchmarks, f is arr.shape[0] and n is the repeating count:

enter image description here

Ali_Sh
  • 2,667
  • 3
  • 43
  • 66
1

This can be done using Pillow (fork of PIL) as follows:

from PIL import Image
import numpy as np
n = 3 # repeatation
im = Image.fromarray(arr)
up_im = im.resize((im.width*n, im.height*n),resample=Image.NEAREST)
up_arr = np.array(up_im)

Example:

arr = np.array(
  [[0, 0, 0, 1, 1],
   [0, 1, 1, 1, 1],
   [1, 1, 0, 0, 1],
   [0, 0, 1, 0, 1],
   [0, 1, 1, 0, 1]])

res (n=3):
np.array(
  [[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
   [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
   [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
   [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
   [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
   [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
   [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1],
   [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
   [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
   [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1],
   [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1],
   [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1],
   [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1]])

numba vs PIL all

numba vs PIL with f=70

numba is by far the most performant in terms of speed. As the matrix size increases, PIL takes much more time.

MSS
  • 3,306
  • 1
  • 19
  • 50