Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slicing a NumPy array within a loop [duplicate]

I need a good explanation (reference) to explain NumPy slicing within (for) loops. I have three cases.

def example1(array):
    for row in array:
        row = row + 1
    return array

def example2(array):
    for row in array:
        row += 1
    return array

def example3(array):
    for row in array:
        row[:] = row + 1
    return array

A simple case:

ex1 = np.arange(9).reshape(3, 3)
ex2 = ex1.copy()
ex3 = ex1.copy()

returns:

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

>>> example2(ex2)
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

>>> example3(ex3)
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

It can be seen that the first result differs from the second and third.

like image 992
blaz Avatar asked Mar 17 '16 09:03

blaz


People also ask

How do you repeat an array in NumPy?

NumPy: repeat() function The repeat() function is used to repeat elements of an array. Input array. The number of repetitions for each element. repeats is broadcasted to fit the shape of the given axis.

Can you slice a NumPy array?

You can slice a range of elements from one-dimensional numpy arrays such as the third, fourth and fifth elements, by specifying an index range: [starting_value, ending_value] . Note that the index structure is inclusive of the first index value, but not the second index value.

Is a NumPy array an iterable?

Numpy with PythonIt is an efficient multidimensional iterator object using which it is possible to iterate over an array. Each element of an array is visited using Python's standard Iterator interface.

Is it possible to create an array from a tuple in NumPy?

The asarray() method in NumPy can be used to create an array from data that already exists in the form of lists or tuples.


2 Answers

First example:

You extract a row and add 1 to it. Then you redefine the pointer row but not what the array contains! So it will not affect the original array.

Second example:

You make an in-place operation - obviously this will affect the original array - as long as it is an array.

If you were doing a double loop it wouldn't work anymore:

def example4(array):
    for row in array:
        for column in row:
            column += 1
    return array

example4(np.arange(9).reshape(3,3))
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

this doesn't work because you don't call np.ndarray's __iadd__ (to modify the data the array points to) but the python int's __iadd__. So this example only works because your rows are numpy arrays.

Third example:

row[:] = row + 1 this is interpreted as something like row[0] = row[0]+1, row[1] = row[1]+1, ... again this works in place so this affects the original array.

Bottom Line

If you are operating on mutable objects, like lists or np.ndarray you need to be careful what you change. Such an object only points to where the actual data is stored in memory - so changing this pointer (example1) doesn't affect the saved data. You need to follow the pointer (either directly by [:] (example3) or indirectly with array.__iadd__ (example2)) to change the saved data.

like image 90
MSeifert Avatar answered Oct 23 '22 21:10

MSeifert


In the first code, you don't do anything with the new computed row; you rebind the name row, and there is no connection to the array anymore.

In the second and the third, you dont rebind, but assign values to the old variable. With += some internal function is called, which varies depending on the type of the object you let it act upon. See links below.

If you write row + 1 on the right hand side, a new array is computed. In the first case, you tell python to give it the name row (and forget the original object which was called row before). And in the third, the new array is written to the slice of the old row.

For further reading follow the link of the comment to the question by @Thiru above. Or read about assignment and rebinding in general...

like image 27
Ilja Avatar answered Oct 23 '22 21:10

Ilja