Tuesday, February 26, 2019

NumPy library - 4 (Indexing, Slicing, and Iterating)

This post will help you to learn how to select elements through indexes and slices in order to obtain the values contained in them. This value can be used to make assignments in order to change their values and to make iterations within them.

Indexing

You might be familiar with the indexing in arrays if you have learnt any programming language. Array indexing always uses square brackets ([ ]) to index the elements of the array so
that the elements can then be referred individually for various purposes such as:
  • extracting a value
  • selecting items
  • assigning a new value
An array index starts at zero, thus if I create an array :

arr1 = np.arange(1,5)

The created array [1 2 3 4] has four elements whose indices are 0,1,2,3. In order to access a single element of an array, you can refer to its index. See the program below :

import numpy as np

arr1 = np.arange(1,5)
print(arr1)
print("\nThe first Element is at [0], it's value is\n")
print(arr1[0])
print("\nThe second Element is at [1], it's value is\n")
print(arr1[1])
print("\nThe third Element is at [2], it's value is\n")
print(arr1[2])
print("\nThe fourth Element is at [3], it's value is\n")
print(arr1[3])


The output of the program is shown below:

[1 2 3 4]

The first Element is at [0], it's value is

1

The second Element is at [1], it's value is

2

The third Element is at [2], it's value is

3

The fourth Element is at [3], it's value is

4
------------------
(program exited with code: 0)

Press any key to continue . . .


In order to access the last element we can us negative indexes which have the same incremental sequence from 0 to –1, –2, and so on, but in practice they cause the final element to move gradually toward the initial element, which will be the one with the more negative index value. Thus arr1[-1] will give the last element of the array. See the program below:

import numpy as np

arr1 = np.arange(1,5)
print(arr1)
print("\nThe last Element is at [-1], it's value is\n")
print(arr1[-1])
print("\nThe second last Element is at [-2], it's value is\n")
print(arr1[-2])
print("\nThe third last Element is at [-3], it's value is\n")
print(arr1[-3])
print("\nThe first Element is at [-4], it's value is\n")
print(arr1[-4])



The output of the program is shown below:

[1 2 3 4]

The last Element is at [-1], it's value is

4

The second last Element is at [-2], it's value is

3

The third last Element is at [-3], it's value is

2

The first Element is at [-4], it's value is

1
------------------
(program exited with code: 0)


Press any key to continue . . .

It is also possible to select multiple elements of an array as shown in the following program:

import numpy as np

arr1 = np.arange(1,9)
print(arr1)
print("\nThe values of selected Elements  [1,2,3,-1,-2] are\n")
print(arr1[[1,2,3,-1,-2]])
 

The output of the program is shown below:

[1 2 3 4 5 6 7 8]

The values of selected Elements  [1,2,3,-1,-2] are

[2 3 4 8 7]


------------------
(program exited with code: 0)

Press any key to continue . . .


Now let's focus on two dimensional arrays (matrices) which are represented as rectangular arrays consisting of rows and columns, defined by two axes, where axis 0 is represented by the rows and axis 1 is represented by the columns. The indexing in this case is represented by a pair of values: the first value is the index of the row and the second is the index of the column, which are inside a square bracket as shown: [row index, column index].  In this case also indexing starts from zero hence the first item will [0,0], second item in first row and second column will be [0,1] and so on..

The following program creates a two dimensional array and access the element from a specified location:

import numpy as np

arr = np.arange(1,10).reshape(3,3)
print(arr)

print("\nThe elements of the array are:\n")
print(arr[0,0])
print(arr[0,1])
print(arr[0,2])
print(arr[1,0])
print(arr[1,1])
print(arr[1,2])
print(arr[2,0])
print(arr[2,1])
print(arr[2,2])


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]


The elements of the array are:

1
2
3
4
5
6
7
8
9
------------------
(program exited with code: 0)

Press any key to continue . . . 


Slicing

We have seen Python list slicing before and the same concept is used to extract portions of an array to generate new arrays. In case of Python lists the resulting array after slicing are copies but in NumPy the resulting arrays are views of the same underlying buffer. The syntax of slicing is [index of the starting element:index of the final element]

The following program extract a portion of the array from second to the sixth element:

import numpy as np

arr = np.arange(1,10)
print(arr)

print("\nThe elements of the array are:\n")
print(arr[1:5])


The output of the program is shown below:

[1 2 3 4 5 6 7 8 9]

The elements of the array are:

[2 3 4 5]
------------------
(program exited with code: 0)

Press any key to continue . . . 


Slicing can be done by specifying different slicing conditions for example we can use a third number that defines the gap in the sequence of the elements. Thus to access the elements in an alternating fashion we can use arr[1:5:2] in our previous program as shown below:

import numpy as np

arr = np.arange(1,10)
print(arr)

print("\nThe elements of the array in alternate fashion are:\n")
print(arr[1:7:2])


The output of the program is shown below:

[1 2 3 4 5 6 7 8 9]

The elements of the array in alternate fashion are:

[2 4 6]

------------------
(program exited with code: 0)

Press any key to continue . . .

Now let's see what happens when we omit the first,second and last values in the slicing condition:

import numpy as np

arr = np.arange(1,10)
print(arr)

print("\nThe elements of the array as per slicing conditions are:\n")
print(arr[1:7:2])
print("\nThe elements of the array If you omit the first number are:\n")
print(arr[:7:2])
print("\nThe elements of the array If you omit the second number are:\n")
print(arr[1::2])
print("\nThe elements of the array If you omit the third number are:\n")
print(arr[1:7:])
print("\nThe elements of the array If you omit the first and second number are:\n")
print(arr[::2])
print("\nThe elements of the array If you omit the second and third number are:\n")
print(arr[1::])
print("\nThe elements of the array If you omit the first and third number are:\n")
print(arr[:7:])


The output of the program is shown below:

[1 2 3 4 5 6 7 8 9]

The elements of the array as per slicing conditions are:

[2 4 6]

The elements of the array If you omit the first number are:

[1 3 5 7]

The elements of the array If you omit the second number are:

[2 4 6 8]

The elements of the array If you omit the third number are:

[2 3 4 5 6 7]

The elements of the array If you omit the first and second number are:

[1 3 5 7 9]

The elements of the array If you omit the second and third number are:

[2 3 4 5 6 7 8 9]

The elements of the array If you omit the first and third number are:

[1 2 3 4 5 6 7] 


------------------
(program exited with code: 0)

Press any key to continue . . .


The output of the program shows that if we omit the first number, NumPy implicitly interprets this number as 0 (i.e., the initial element of the array). If we omit the second number, this will be interpreted as the maximum index of the array; and if we omit the last number this will be interpreted as 1 which means all the elements will be considered without intervals.

Now let's see how slicing is done with the two-dimensional arrays. In this case the slicing syntax is separately defined for the rows and columns. The following program better explains how to perform slicing in two-dimensional arrays:

import numpy as np

arr = np.arange(1,10).reshape(3,3)
print(arr)
print("\nThe elements of the first row are:\n")
print(arr[0,:])
print("\nThe elements of the first column are:\n")
print(arr[:,0])
print("\nThe elements of the second row are:\n")
print(arr[1,:])
print("\nThe elements of the second column are:\n")
print(arr[:,1])
print("\nThe elements of the second row are:\n")
print(arr[2,:])
print("\nThe elements of the second column are:\n")
print(arr[:,2])


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]

The elements of the first row are:

[1 2 3]

The elements of the first column are:

[1 4 7]

The elements of the second row are:

[4 5 6]

The elements of the second column are:

[2 5 8]

The elements of the second row are:

[7 8 9]

The elements of the second column are:

[3 6 9]


------------------
(program exited with code: 0)

Press any key to continue . . .


In order to extract a smaller matrix from the original need to explicitly define all intervals with indexes that define them as shown in the program:

import numpy as np

arr = np.arange(1,10).reshape(3,3)
print(arr)
print('\n')
print(arr[0:1,0:2])
print('\n')
print(arr[0:2,0:2])
print('\n')
print(arr[1:2,1:2])


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]


[[1 2]]

[[1 2]
 [4 5]]


[[5]]


------------------
(program exited with code: 0)

Press any key to continue . . .


In case if the indexes of the rows or columns to be extracted are not contiguous, we can specify an array of indexes as shown in the following program:

import numpy as np

arr = np.arange(1,10).reshape(3,3)
print(arr)
print('\n')
print(arr[[0,2],0:2])


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]


[[1 2]
 [7 8]]

------------------
(program exited with code: 0)

Press any key to continue . . .

Iterating an Array

The iteration of the items in an array can be done using the For loop . Let's perform iteration of a one dimensional array, see the following program:

import numpy as np

arr = np.arange(1,10)
print(arr)
print('\nPrinting array items\n')

for i in arr:
  
    print(i)






The output of the program is shown below:

[1 2 3 4 5 6 7 8 9]

Printing array items

 
1
2
3
4
5
6
7
8
9


------------------
(program exited with code: 0)

Press any key to continue . . . 


If we apply the for loop to a two-dimensional array it will always perform a scan according to the first axis as shown in the program:

import numpy as np

arr = np.arange(1,10).reshape(3,3)
print(arr)
print('\nPrinting array items\n')

for i in arr:
   
    print(i)



The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]

Printing array items

[1 2 3]
[4 5 6]
[7 8 9]
------------------
(program exited with code: 0)

Press any key to continue . . . 


Thus an element by element iteration is not done. NumPy has special construct to perform this iteration as shown in this program:

import numpy as np

arr = np.arange(1,10).reshape(3,3)
print(arr)
print('\nPrinting array items\n')

for i in arr.flat:
   
    print(i)


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]

Printing array items

1
2
3
4
5
6
7
8
9
------------------
(program exited with code: 0)

Press any key to continue . . .


NumPy has a special apply_along_axis() function to manage the iterations. This function takes three arguments: the aggregate function, the axis on which to apply the iteration, and the array. If the option axis equals 0, then the iteration evaluates the elements column by column, whereas if axis equals 1 then the iteration evaluates the elements row by row. The following program uses this function:

import numpy as np

arr1 = np.arange(1,10).reshape(3,3)
print(arr1)
print('\nPrinting array items\n')
print(np.apply_along_axis(np.mean, axis=0, arr=arr1))
print('\nPrinting array items\n')
print(np.apply_along_axis(np.mean, axis=1, arr=arr1))


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]

Printing array items

[4. 5. 6.]

Printing array items

[2. 5. 8.]


------------------
(program exited with code: 0)

Press any key to continue . . .


The above program calculate the average values first by column and then by row. We can also use ufunctions as the first argument in the apply_along_axis() function as shown in the following program:

import numpy as np

arr1 = np.arange(1,10).reshape(3,3)
print(arr1)
print('\nPrinting array items\n')
print(np.apply_along_axis(np.sqrt, axis=0, arr=arr1))
print('\nPrinting array items\n')
print(np.apply_along_axis(np.max, axis=0, arr=arr1))
print('\nPrinting array items\n')
print(np.apply_along_axis(np.min, axis=0, arr=arr1))
print('\nPrinting array items\n')
print(np.apply_along_axis(np.log, axis=0, arr=arr1))


The output of the program is shown below:

[[1 2 3]
 [4 5 6]
 [7 8 9]]

Printing array items

[[1.         1.41421356 1.73205081]
 [2.         2.23606798 2.44948974]
 [2.64575131 2.82842712 3.        ]]

Printing array items

[7 8 9]

Printing array items

[1 2 3]

Printing array items

[[0.         0.69314718 1.09861229]
 [1.38629436 1.60943791 1.79175947]
 [1.94591015 2.07944154 2.19722458]]


------------------
(program exited with code: 0)

Press any key to continue . . .

Here I am ending today's post. In the next post we shall further explore NumPy library and continue with indexing and slicing. Till we meet next keep practicing and learning Python as Python is easy to learn!









Share:

0 comments:

Post a Comment