# NumPy Array Indexing

Numpy is a python package that stands for ‘Numerical Python’. It is mainly used for scientific computing, including linear algebra, random number generation, and matrix operations. One of the most commonly used features in Numpy is Numpy Array Indexing. Numpy Array Indexing is the process through which we can access a specific element or a subset of elements in the Numpy arrays. In this tutorial, we will explore Numpy Array indexing and its different methods, including indexing using integers, indexing using boolean arrays, and indexing using slices.

## Indexing using Integers

When you index a Numpy array using integers, it returns a specific element at the specified location in the array. You can index using integers in two different ways:

### Single Integer Indexing

In single integer indexing, you specify a single integer for indexing the array. The index starts from 0 and goes up to N-1 (where N is the number of elements in the array). Here is an example:

```import numpy as np
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(arr[3])```

Output:

`3`

In the above example, we created a Numpy array with ten elements and accessed the fourth element (with index 3) using single integer indexing. The output shows that the value of the fourth element is 3.

### Multiple Integer Indexing

In multiple integer indexing, you specify a tuple of integers for indexing the array. The tuple represents the indices of the elements that you want to access in the array. Here is an example:

```import numpy as np
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
print(arr[(0,2)])```

Output:

`2`

In the above example, we created a two-dimensional Numpy array with three rows and three columns and accessed the first element in the first row and the last element in the third row using multiple integer indexing. The output shows that the value of the accessed element is 2.

## Indexing using Boolean Arrays

When you index a Numpy array using boolean arrays, it returns a subset of the elements that meet a specified condition. You can index using boolean arrays in the following way:

### Boolean Indexing

In boolean indexing, you specify a boolean array of the same shape as the original array for indexing the array. Each element in the boolean array corresponds to an element in the original array. If the value of the element in the boolean array is True, then the corresponding element in the original array is included in the subset array. Here is an example:

```import numpy as np
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
subset_arr = arr[arr>5]
print(subset_arr)```

Output:

`[6 7 8 9]`

In the above example, we created a Numpy array with ten elements and extracted a subset of the elements that are greater than 5 using boolean indexing. The output shows that the subset array contains the elements 6, 7, 8, and 9.

## Indexing using Slices

When you index a Numpy array using slices, it returns a subset of the elements that fall within a specified range. You can index using slices in the following ways:

### Single Slicing

In single slicing, you specify a single slice object for indexing the array. The slice object consists of a start index, an end index, and a step size. The start index is the index of the first element in the subset, the end index is the index of the last element in the subset (non-inclusive), and the step size is the number of elements between each two consecutive elements in the subset. Here is an example:

```import numpy as np
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
subset_arr = arr[2:8:2]
print(subset_arr)```

Output:

`[2 4 6]`

In the above example, we created a Numpy array with ten elements and extracted a subset of the elements from the third element to the ninth element (inclusive) with a step size of 2 using single slicing. The output shows that the subset array contains the elements 2, 4, and 6.

### Multiple Slicing

In multiple slicing, you specify multiple slice objects for indexing the array. Each slice object represents a dimension in the Numpy array. Here is an example:

```import numpy as np
arr = np.array([[ 0,  1,  2,  3,  4],
[ 5,  6,  7,  8,  9],
[10, 11, 12, 13, 14]])
subset_arr = arr[1:3, 2:5]
print(subset_arr)```

Output:

```[[ 7  8  9]
[12 13 14]]```

In the above example, we created a two-dimensional Numpy array with three rows and five columns and extracted a subset of the elements from the second and the third rows and from the third to the fifth columns using multiple slicing. The output shows that the subset array contains the elements 7, 8, 9, 12, 13, and 14.

Advanced slicing is a technique that allows you to access non-contiguous elements in a Numpy array. It is different from the other indexing methods in that it creates a copy of the original array instead of a view. Here is an example:

```import numpy as np
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
indices = [1, 3, 5, 7]
subset_arr = arr[indices]
print(subset_arr)```

Output:

`[1 3 5 7]`

In the above example, we created a Numpy array with ten elements and extracted a subset of the elements using a list of indices. The output shows that the subset array contains the elements with indices 1, 3, 5, and 7.

## Conclusion

In this tutorial, we explored Numpy Array indexing and its different methods, including indexing using integers, indexing using boolean arrays, and indexing using slices. Numpy Array indexing can be used for many purposes, such as data manipulation, data cleaning, data filtering, and data analysis. To become proficient in Numpy Array indexing, it is important to practice and experiment with the different methods on various types of Numpy arrays.