Home > Software engineering >  Get each item while slicing (:) a numpy matrix
Get each item while slicing (:) a numpy matrix

Time:10-26

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]]]])
  • Related