I have been looking for a solution to this for a while. I am trying to use as few loops in my code as possible, so I've been trying to set slices of the numpy arrays instead.
I have a large array of size (s, s, s, s), but you can think of it as storing 2d sxs arrays inside of each spot in a larger sxs array.
I want to store, in each spot in the larger array, a small sxs full of the scalar value from other_array[location inside big array].
For example, let's imagine a big 2x2 array containing 2x2 arrays at each spot. At the spot (0,0), I need to create a 2x2 array full of other_array[(0,0)] values.
What is a simple way to do this using array slicing? Here is what I want to simplify:
pair_values = np.zeros((num_s, num_s, num_s, num_s))
for x in range(num_s):
for y in range(num_s):
pair_values[x,y] = np.full((num_s, num_s), values[(x, y)])
Right now this is my code, but I have no idea what to put for the index of my "values" array:
pair_values = np.zeros((num_s, num_s, num_s, num_s))
pair_values[:, :] = np.full((num_s, num_s), values[?])
Please let me know if this is confusingly explained and I will try to rephrase. Essentially the question is how to use each index when slicing with (:).
CodePudding user response:
Your iteration produces:
In [12]: num_s=2
In [15]: values = np.arange(1,5).reshape(2,2)*10
In [16]: pair_values = np.zeros((num_s, num_s, num_s, num_s))
...: for x in range(num_s):
...: for y in range(num_s):
...: pair_values[x,y] = np.full((num_s, num_s), values[(x, y)])
...:
In [17]: pair_values
Out[17]:
array([[[[10., 10.],
[10., 10.]],
[[20., 20.],
[20., 20.]]],
[[[30., 30.],
[30., 30.]],
[[40., 40.],
[40., 40.]]]])
Where for a pair of indices:
In [18]: pair_values[0,1]
Out[18]:
array([[20., 20.],
[20., 20.]])
In [19]: values[0,1]
Out[19]: 20
First stab at filling the whole array at once:
In [20]: res = np.zeros((num_s,num_s,num_s,num_s))
In [21]: res[:,:] = values
In [22]: res
Out[22]:
array([[[[10., 20.],
[30., 40.]],
[[10., 20.],
[30., 40.]]],
[[[10., 20.],
[30., 40.]],
[[10., 20.],
[30., 40.]]]])
Wrong layout - though we could use transpose
to get the right one.
But by adding dimensions to values
we get it to broadcast
as desired:
In [23]: res[:,:] = values[:,:,None,None]
In [24]: res
Out[24]:
array([[[[10., 10.],
[10., 10.]],
[[20., 20.],
[20., 20.]]],
[[[30., 30.],
[30., 30.]],
[[40., 40.],
[40., 40.]]]])
Another way is tile
(or repeat
) that expanded values
array:
In [25]: np.tile(values[:,:,None,None],(1,1,num_s,num_s))
Out[25]:
array([[[[10, 10],
[10, 10]],
[[20, 20],
[20, 20]]],
[[[30, 30],
[30, 30]],
[[40, 40],
[40, 40]]]])