Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest way to insert a 2D array into a (larger) 2D array

Tags:

python

numpy

Say there's two 2D arrays, a and b

import numpy as np
a = np.random.rand(3, 4)
b = np.random.zeros(8, 8)

and b is always larger than a over both axes.

(Edit: b is initialized as an array of zeros, to reflect the fact that all elements not occupied by a will remain zero.)

Question. What's the fastest or most Pythonic way to "insert" a into b?

So far I've tried 2 things:

  1. Using np.pad to "turn" a into an array of shape (8, 8)
  2. Loop through every row in a and place it in some the corresponding row in b

What I haven't tried is using a doubly-nested loop to iterate over every element of a, since I think that's not performance-friendly.

Motivation. Each array a is a tiny character, and I'd like to feed each character to a neural net that accepts flattened arrays of shape (8, 8), ie. arrays of shape (64,). (I think I can't simply flatten a to one dimension and pad it with zeros because then its two-dimensional structure gets warped, so, rather, I must first "reshape" it into (8, 8), right?) There's a few millions of characters.

like image 828
étale-cohomology Avatar asked Dec 19 '22 13:12

étale-cohomology


2 Answers

What about :

b[:a.shape[0],:a.shape[1]] = a

Note I assumed a is to be placed at the begining of b but you could refine it a bit to put a anywhere:

a0,a1=1,1
b[a0:a0+a.shape[0],a1:a1+a.shape[1]] = a
like image 67
jadsq Avatar answered Jan 28 '23 05:01

jadsq


More generally you can determine the position where you want to insert the array if you create a tuple of slices (this works for arbitary dimensions):

>>> a = np.random.random((5,5))
>>> b = np.ones((3,3))

>>> edge_coordinate = (0,0)
>>> slicer = tuple(slice(edge, edge+i) for edge, i in zip(edge_coordinate, b.shape))
>>> a[slicer] = b
>>> a
array([[ 1.        ,  1.        ,  1.        ,  0.14206495,  0.36385016],
       [ 1.        ,  1.        ,  1.        ,  0.08861402,  0.7888898 ],
       [ 1.        ,  1.        ,  1.        ,  0.1975496 ,  0.13345192],
       [ 0.550487  ,  0.22471952,  0.47050879,  0.04669643,  0.13480528],
       [ 0.25139511,  0.06499812,  0.42247189,  0.05840351,  0.74735495]])

by varying the edge_coordinate you can vary the position:

>>> a = np.random.random((5,5))
>>> b = np.ones((3,3))

>>> edge_coordinates = (1,1)  # changed
>>> slicer = tuple(slice(edge, edge+i) for edge, i in zip(edge_coordinates, b.shape))
>>> a[slicer] = b
>>> a
array([[ 0.21385714,  0.68789872,  0.3915475 ,  0.67342566,  0.05642307],
       [ 0.19778658,  1.        ,  1.        ,  1.        ,  0.70717406],
       [ 0.73678924,  1.        ,  1.        ,  1.        ,  0.90285997],
       [ 0.39709332,  1.        ,  1.        ,  1.        ,  0.96959814],
       [ 0.89627195,  0.21295355,  0.72598992,  0.80749348,  0.76660287]])

Ideally one could make a function of it - if you regularly use it.

like image 42
MSeifert Avatar answered Jan 28 '23 04:01

MSeifert