fpalka
fpalka

Reputation: 23

Python numpy insert column at the beginning and at the end of matrix

I need to append boundaries to my matrix, it's just a repetition of first column and row on the beginning and last column and row at the end of matrix.

I have this PoC:

matrix = np.arange(20).reshape(4,5)

[[ 0  1  2  3  4]                                                                                                                             
 [ 5  6  7  8  9]                                                                                                                             
 [10 11 12 13 14]                                                                                                                             
 [15 16 17 18 19]]

And when I insert rows at the top and bottom like this, it works fine.

shape = matrix.shape (4,5)
matrix_t = np.insert(matrix, [0, shape[0]], [matrix[0], matrix[shape[0]-1]], axis=0)

[[ 0  1  2  3  4]                                                                                                                             
 [ 0  1  2  3  4]                                                                                                                             
 [ 5  6  7  8  9]                                                                                                                             
 [10 11 12 13 14]                                                                                                                             
 [15 16 17 18 19]                                                                                                                             
 [15 16 17 18 19]]

As you can see it has added 0 1 2 3 4 as first row and 15 16 17 18 19 as last.

Now I wanted to do same thing just to append columns on the left and on the right. Simplifying above code a bit, I did it like this (needed to reshape to create column vector).

temp1 = np.arange(4).reshape(4,1)
temp2 = np.arange(4, 8, 1).reshape(4,1)
matrix_t = np.insert(matrix, [0, 5], [temp1, temp2], axis=1)

And then i got this error:

Traceback (most recent call last):                                                                                                            
  File "main.py", line 33, in <module>                                                                                                        
    matrix_t = np.insert(matrix, [0, 5], [temp1, temp2], axis=1)                                                                              
  File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 3496, in insert                                                      
    new[slobj] = values                                                                                                                       
ValueError: total size of new array must be unchanged

When i do it like this, it works perfectly fine:

matrix_t = np.insert(matrix, [0, 5], temp1, axis=1)

[[ 0  0  1  2  3  4  0]                                                                                                                       
 [ 1  5  6  7  8  9  1]                                                                                                                       
 [ 2 10 11 12 13 14  2]                                                                                                                       
 [ 3 15 16 17 18 19  3]]

What am I missing?

Upvotes: 2

Views: 1323

Answers (1)

hpaulj
hpaulj

Reputation: 231385

The insert docs:

values : array_like
    Values to insert into `arr`. If the type of `values` is different
    from that of `arr`, `values` is converted to the type of `arr`.
    `values` should be shaped so that ``arr[...,obj,...] = values``
    is legal.

your start array:

In [40]: arr = np.arange(20).reshape(4,5)  

adding new rows:

In [42]: np.insert(arr, [0, 4], [arr[0], arr[-1]], axis=0)                                     
Out[42]: 
array([[ 0,  1,  2,  3,  4],
       [ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [15, 16, 17, 18, 19]])

That values specification means that these two match:

In [48]: np.array([arr[0], arr[-1]])                                                           
Out[48]: 
array([[ 0,  1,  2,  3,  4],
       [15, 16, 17, 18, 19]])
In [49]: Out[42][[0,4],:]                                                                      
Out[49]: 
array([[ 0,  1,  2,  3,  4],
       [15, 16, 17, 18, 19]])

values isn't a list; it's array_like, meaning that insert will create an array from that input.

When we try to add new columns:

In [50]: temp1 = np.arange(4).reshape(4,1) 
    ...: temp2 = np.arange(4, 8, 1).reshape(4,1) 
    ...: np.insert(arr, [0, 5], [temp1, temp2], axis=1)                                        
---------------------------------------------------------------------------
...
ValueError: shape mismatch: value array of shape (2,4,1) could not be broadcast to indexing result of shape (2,4)

A different message, but same problem. Look at the array version of your values list:

In [51]: np.array([temp1, temp2])                                                              
Out[51]: 
array([[[0],
        [1],
        [2],
        [3]],

       [[4],
        [5],
        [6],
        [7]]])

That's the (2,4,1) array. It's trying to put that into a (2,4) slot:

In [52]: np.ones((4,7),int)[:,[0,5]]                                                           
Out[52]: 
array([[1, 1],
       [1, 1],
       [1, 1],
       [1, 1]])

If we join the temp on axis 1, to make a (2,4) array, the insert works:

In [53]: np.concatenate([temp1,temp2], axis=1)                                                 
Out[53]: 
array([[0, 4],
       [1, 5],
       [2, 6],
       [3, 7]])

In [54]: np.insert(arr, [0, 5], Out[53], axis=1)                                               
Out[54]: 
array([[ 0,  0,  1,  2,  3,  4,  4],
       [ 1,  5,  6,  7,  8,  9,  5],
       [ 2, 10, 11, 12, 13, 14,  6],
       [ 3, 15, 16, 17, 18, 19,  7]])

np.insert is general purpose, trying to handle lots of cases, and as such understanding the inputs can be tricky.

===

Your first insert could just as easily be done with indexing or concatenate (vstack for simpler notation):

In [56]: arr[[0]+[0,1,2,3]+[3]]                                                                
Out[56]: 
array([[ 0,  1,  2,  3,  4],
       [ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [15, 16, 17, 18, 19]])
In [57]: np.vstack([arr[0],arr,arr[-1]])                                                       
Out[57]: 
array([[ 0,  1,  2,  3,  4],
       [ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14],
       [15, 16, 17, 18, 19],
       [15, 16, 17, 18, 19]])

np.concatenate([arr[[0]],arr,arr[[-1]]]) is the same, where arr[[0]] is (1,5) shaped.

And the column insert with a column concatenate (temp1 already has the (4,1) shape):

In [58]: np.concatenate([temp1, arr, temp2], axis=1)                                           
Out[58]: 
array([[ 0,  0,  1,  2,  3,  4,  4],
       [ 1,  5,  6,  7,  8,  9,  5],
       [ 2, 10, 11, 12, 13, 14,  6],
       [ 3, 15, 16, 17, 18, 19,  7]])

Upvotes: 1

Related Questions