NumPy - Array Indexing
In this tutorial, you will learn the followings
- What is Array Indexing in NumPy?
- Difference between Indexing and Slicing in NumPy Array
- Types of Array Indexing in Numpy
- Negative Indexing in NumPy Array
- Array Slicing in NumPy
- Boolean indexing in NumPy Array
- Fancy Indexing in NumPy Array
What is Array Indexing in NumPy?
NumPy array indexing refers to the ability to access and manipulate specific elements, rows, columns, or sections of a NumPy array. NumPy is a library in Python that provides support for large, multi-dimensional arrays and matrices, along with a collection of mathematical functions to operate on these arrays. Indexing in NumPy is a zero-based system, which means that the first element has an index of 0.
Difference between Indexing and Slicing in NumPy Array
In NumPy, both array indexing and slicing allow you to access and manipulate data within a NumPy array. However, they operate in slightly different ways:
1. Array Indexing: Array indexing in NumPy refers to accessing a specific element in the array using its integer index. Indices start at 0, meaning the first element is accessed with the index 0, the second with the index 1, and so on. If you have a multi-dimensional array, you can access elements by using a comma-separated tuple of indices. For example, in a 2D array a, you can access the element at the first row and second column using a[0, 1]. Array indexing returns a single value if the array is one-dimensional or a reduced array if the array is multi-dimensional.

2. Array Slicing: Slicing in NumPy refers to accessing a subset or a range of elements in the array. The slice syntax uses the colon (:) operator and can be used to access a range of elements in the array. For example, a[1:4] would access elements from index 1 up to, but not including, index 4. Slicing can be used with multiple dimensions too. For instance, a[1:4, 0:2] would give you a 2D sub-array from the second to fourth row and first two columns. Importantly, slicing in NumPy returns a view of the original array, not a copy, which means that modifying a slice also changes the original array.

Overall, array indexing is used when you need to access or change a specific element or elements, while slicing is used when you need to access or change a range or subsection of an array.
Types of Array Indexing in Numpy
Here are some ways to use indexing in NumPy:
-
Integer indexing: Allows you to select any item in the array by its N-dimensional index. For example, in a 1D array
a, the first element can be accessed bya[0], the second bya[1], and so on. -
Slicing: Similar to Python lists, NumPy arrays can be sliced. Since arrays may be multidimensional, you must specify a slice for each dimension of the array. For example,
a[1:5]gives you the elements from index 1 to index 4 (5 is exclusive) in the arraya. -
Boolean indexing: This allows you to select elements based on conditions. For example,
a[a > 2]returns all elements inathat are greater than 2. -
Fancy indexing (also known as Integer Array Indexing): This type of indexing allows you to access multiple elements at once by providing the indices in an array or list. For example, if
ais a 1D array,a[[1, 3, 5]]would return an array that contains the elements at indices 1, 3, and 5.
These indexing methods can be used not just for accessing values but also for modifying values, making them very powerful tools for data manipulation in NumPy.
Integer Indexing
Integer indexing in NumPy refers to the process of accessing specific elements in an array by specifying their integer indices.
Access 1-D Array
In a 1-dimensional array, each element has a unique index which is an integer, starting from 0 for the first element. For instance:
import numpy as np
# 1D array
arr1D = np.array([1, 2, 3, 4, 5])
# Access third element
print(arr1D[2]) # outputs: 3
Access 2-D Arrays
In a 2-dimensional array (or matrix), each element is identified by a pair of indices, where the first index denotes the row and the second index denotes the column:
# 2D array
arr2D = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Access element in second row, third column
print(arr2D[1, 2]) # outputs: 6
Access 3-D Arrays
In a 3-dimensional array, each element is identified by a triplet of indices, where the first index is the number of the depth layer (Matrix Number), the second index denotes the row, and the third index denotes the column:
# 3D array
arr3D = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
# Access element in first "Matrix", second row, third column
print(arr3D[0, 1, 2]) # outputs: 6
Negative Indexing in NumPy Arrays
In Python and many other languages, arrays can be indexed using negative numbers, and NumPy arrays in Python are no exception. Negative indexing refers to accessing elements from the end of an array, starting from -1, which corresponds to the last element.
Let's take an example of a 1-D numpy array:
import numpy as np
# Create a 1-D numpy array
arr = np.array([10, 20, 30, 40, 50])
# Access elements using negative indexing
print(arr[-1]) # Outputs: 50
print(arr[-2]) # Outputs: 40
print(arr[-3]) # Outputs: 30
Negative Indexing in 2-D Arrays
This concept can be extended to multi-dimensional arrays. In 2D arrays, the first index corresponds to the row and the second to the column.

# Create a 2-D numpy array
arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# Access elements using negative indexing
print(arr_2d[-1, -1]) # Outputs: 12
print(arr_2d[-2, -3]) # Outputs: 6
Here, arr_2d[-1, -1] gives you the last element of the last row, arr_2d[-2, -3] gives you the third last element of the second to last row, and so on.
It's important to note that Python is a zero-indexed language, so the first item is at position 0, not 1. However, for negative indexing, the last item is at position -1, the second last at -2, and so forth. This is why negative indexing can be quite useful: it allows you to easily access the elements at the end of an array without needing to know the exact length of the array.
Array Slicing in NumPy
Slicing in NumPy refers to getting a subset of an array by specifying a range of indices. It's a way to extract a portion of your array for further manipulation or analysis.
The general form of a slice is start:stop:step, where start is the index at which to start the slice, stop is the index at which to end the slice, and step is the number of indices between each element to include in the slice. All three values are optional. If you leave out start, it defaults to the first index (0); if you leave out stop, it defaults to the last index; and if you leave out step, it defaults to 1.
Here is an example of 1D array slicing:
import numpy as np
# Create a 1D array
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# Use slicing to get a subset of the array
subset = arr[1:7:2]
print(subset) # Output: [1 3 5]
2-D Array Slicing
Slicing can also be used with 2D arrays (matrices). In a 2D array, you have two dimensions to slice over: rows and columns.
Here is an example:
# Create a 2D array
matrix = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
# Use slicing to get a subset of the array
subset = matrix[1:, 2:]
print(subset)
#output
# [[ 7 8]
# [11 12]]
In this example, the slice 1: in the row dimension gets all rows starting from the second row, and the slice 2: in the column dimension gets all columns starting from the third column. The intersection of these rows and columns is the 2x2 matrix in the bottom right corner of the original matrix.
Boolean Indexing in NumPy Array
Boolean indexing in NumPy is a type of indexing which allows you to select elements from an array using conditions. In this type of indexing, an array is filled with boolean values - either True or False - which then allows you to select only the values where the corresponding boolean array contains True.
Here's an example where we'll use a boolean condition to select only the even numbers from an array:
import numpy as np
# Create a 1D array
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# Use boolean indexing to select even numbers
even_numbers = arr[arr % 2 == 0]
print(even_numbers) # Output: [0 2 4 6 8]
Fancy Indexing
Fancy indexing, also known as integer array indexing, allows you to access multiple array elements at once using another array or list of indices.
Here's a simple example in a 1D array:
import numpy as np
# Create a 1D array
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# Use fancy indexing
selected_elements = np.array([1, 3, 5])
print(selected_elements) # Output: [1 3 5]
In this example, the indices array is used to select the elements at positions 1, 3, and 5 from arr.
Fancy indexing can also be used with 2D arrays, allowing you to access multiple rows and/or columns at once. Here's an example:
# Create a 2D array
matrix = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Define row and column indices
row_indices = np.array([0, 2])
column_indices = np.array([1, 2])
# Use fancy indexing
selected_elements = matrix[row_indices, column_indices]
print(selected_elements) # Output: [2 9]
In this example, we select elements at positions (0,1) and (2,2) from the matrix, which are 2 and 9, respectively.
Remember that when you use fancy indexing, the shape of the result reflects the shape of the index arrays rather than the shape of the array being indexed. Also, fancy indexing returns a copy of the data, not a view as in typical slicing.