1

I have a ndarray like this one:

number_of_rows = 3
number_of_columns = 3
a = np.arange(number_of_rows*number_of_columns).reshape(number_of_rows,number_of_columns)
a

array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

But I want something like this:

array([[0, 100, 101],
       [3, 102, 103],
       [6, 7, 8]])

To do that I want to avoid to do it one by one, I rather prefer to do it in arrays or matrices, because later I want to extend the code. Nothe I have change a submatrix of the initial matrix (in mathematical terms, in terms of this example ndarray). In the example the columns considered are [1,2] and the rows [0,1].

columns_to_keep = [1,2] 
rows_to_keep = [0,1]

My first try was to do:

a[rows_to_keep,:][:,columns_to_keep] = np.asarray([[100,101],[102,103]])

However this doesn't modify the initial a, I am not having any error, so a=

array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

So I have implemented a piece of code that goes do the job:

b = [[100, 101],[102, 103]]

for i in range(len(rows_to_keep)):
    a[i,columns_to_keep] = b[i]

Al thought the previous lines do the job I am wondering how to do it slicing and in a faster fashion. Also in a way that with:

columns_to_keep = [0,2] 
rows_to_keep = [0,2]

the desired output is

array([[100, 1, 101],
       [3, 4, 5],
       [102, 7, 103]]).

Many thanks!

kmario23
  • 57,311
  • 13
  • 161
  • 150
Rafael Valero
  • 2,736
  • 18
  • 28
  • `a[[1,2],...]` is a copy of `a`. Each indexing operation is performed independently. You need to index rows and columns in one indexing operation. I'd suggest reading up on numpy indexing: https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html. – hpaulj Jan 26 '18 at 17:58

2 Answers2

1

Indexing with lists like [1,2] is called advanced indexing. By itself it produces a copy, not a view. You have to use one indexing expression, not two to assign or change values. That is a[[1,2],:] is a copy, a[[1,2],:][:,[1,2]] += 100 modifies that copy, not the original a.

In [68]: arr = np.arange(12).reshape(3,4)

Indexing with slices; this is basic indexing:

In [69]: arr[1:,2:]
Out[69]: 
array([[ 6,  7],
       [10, 11]])

In [70]: arr[1:,2:] += 100

In [71]: arr
Out[71]: 
array([[  0,   1,   2,   3],
       [  4,   5, 106, 107],
       [  8,   9, 110, 111]])

Doing the same indexing with lists requires arrays that 'broadcast' against each other. ix_ is a handy way of generating these:

In [73]: arr[np.ix_([1,2],[2,3])]
Out[73]: 
array([[106, 107],
       [110, 111]])

In [74]: arr[np.ix_([1,2],[2,3])] -= 100

In [75]: arr
Out[75]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

Here's what ix_ produces - a tuple of arrays, one is (2,1) in shape, the other (1,2). Together they index a (2,2) block:

In [76]: np.ix_([1,2],[2,3])
Out[76]: 
(array([[1],
        [2]]), array([[2, 3]]))
hpaulj
  • 221,503
  • 14
  • 230
  • 353
0

For the continuous rows and columns case, you can use basic slicing like this:

In [634]: a
Out[634]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

In [635]: b = np.asarray([[100, 101],[102, 103]])

In [636]: a[:rows_to_keep[1]+1, columns_to_keep[0]:] = b

In [637]: a
Out[637]: 
array([[  0, 100, 101],
       [  3, 102, 103],
       [  6,   7,   8]])

kmario23
  • 57,311
  • 13
  • 161
  • 150