2.3 NumPy Array Indexing & Slicing
NumPy Array Indexing & Slicing
Once a NumPy array has been created, we often need to access specific values, select rows or columns, extract a portion of the dataset, or filter values according to a condition.
NumPy provides powerful indexing and slicing techniques for these tasks.
- What indexing means in NumPy
- Positive and negative indexing
- Indexing 1D arrays
- Slicing 1D arrays
- Using start, stop and step
- Indexing 2D arrays
- Selecting rows and columns
- 2D slicing
- Boolean indexing
- Conditional filtering
- Combining multiple conditions
- Fancy indexing with integer arrays
- Views and copies
- Practical Data Science examples
1. What Is Indexing?
Indexing means accessing a specific element of an array using its position.
NumPy uses zero-based indexing.
Therefore, the first element has index 0, the second
has index 1, and so on.
import numpy as np
numbers = np.array([10, 20, 30, 40, 50])
print(numbers[0])
print(numbers[1])
print(numbers[4])
Output:
10
20
50
NumPy indexing starts from 0, not 1.
2. Understanding Index Positions
numbers = np.array([10, 20, 30, 40, 50])
The positions are:
Value: 10 20 30 40 50
Index: 0 1 2 3 4
| Index | Value |
|---|---|
0 |
10 |
1 |
20 |
2 |
30 |
3 |
40 |
4 |
50 |
3. Negative Indexing
NumPy also supports negative indices. Negative indexing starts from the end of the array.
numbers = np.array([10, 20, 30, 40, 50])
print(numbers[-1])
print(numbers[-2])
print(numbers[-5])
Output:
50
40
10
The index positions can be visualized as:
Value: 10 20 30 40 50
Positive: 0 1 2 3 4
Negative: -5 -4 -3 -2 -1
-1 always refers to the last element,
-2 to the second-last element, and so on.
4. Invalid Index
Attempting to access an index outside the valid range raises an
IndexError.
numbers = np.array([10, 20, 30])
print(numbers[5])
The array has valid positive indices:
0, 1, 2
Therefore, index 5 is invalid.
For an array containing n elements, the largest
positive index is n - 1.
5. What Is Slicing?
Slicing extracts a sequence or portion of an array.
Syntax
array[start:stop:step]
| Part | Meaning |
|---|---|
start |
Starting index; included. |
stop |
Ending boundary; normally excluded. |
step |
Distance between selected elements. |
6. Basic 1D Slicing
numbers = np.array([10, 20, 30, 40, 50])
print(numbers[1:4])
Output:
[20 30 40]
Indices 1, 2 and 3 are selected. Index 4 is excluded.
NumPy slicing follows the same basic start-inclusive, stop-exclusive convention used by Python sequences.
7. Omitting the Start Index
If start is omitted, slicing begins from the first
element.
numbers = np.array([10, 20, 30, 40, 50])
print(numbers[:3])
Output:
[10 20 30]
8. Omitting the Stop Index
If stop is omitted, slicing continues to the end.
numbers = np.array([10, 20, 30, 40, 50])
print(numbers[2:])
Output:
[30 40 50]
9. Copying with a Full Slice
numbers = np.array([10, 20, 30, 40, 50])
result = numbers[:]
print(result)
Output:
[10 20 30 40 50]
Note that numbers[:] is a slice and generally produces
a view rather than an independent copy.
10. Slicing with Step
numbers = np.array([10, 20, 30, 40, 50, 60])
print(numbers[::2])
Output:
[10 30 50]
The step value 2 selects every second element.
11. More Slicing Examples
numbers = np.array([10, 20, 30, 40, 50, 60, 70])
print(numbers[1:6:2])
print(numbers[::3])
Output:
[20 40 60]
[10 40 70]
12. Reversing an Array
A negative step can be used to traverse an array in reverse.
numbers = np.array([10, 20, 30, 40, 50])
print(numbers[::-1])
Output:
[50 40 30 20 10]
array[::-1] is a common way to reverse a NumPy
array.
13. Indexing a 2D Array
A two-dimensional array contains rows and columns.
matrix = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])
The structure is:
Column
0 1 2
Row 0 10 20 30
Row 1 40 50 60
Row 2 70 80 90
An individual element can be accessed using:
array[row, column]
14. Accessing Individual 2D Elements
matrix = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])
print(matrix[0, 0])
print(matrix[1, 2])
print(matrix[2, 1])
Output:
10
60
80
For example:
matrix[1, 2]
means:
- Row index =
1 - Column index =
2 - Value =
60
15. Alternative 2D Indexing Syntax
NumPy also supports nested indexing.
matrix[1][2]
This accesses the same element as:
matrix[1, 2]
matrix[row, column] is generally preferred for
NumPy because it directly expresses multidimensional
indexing.
16. Selecting a Complete Row
matrix = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])
print(matrix[1, :])
Output:
[40 50 60]
The colon means all columns.
The following is also commonly used:
print(matrix[1])
17. Selecting a Complete Column
print(matrix[:, 1])
Output:
[20 50 80]
Here:
:means all rows.1selects column index 1.
matrix[row, column]
matrix[:, column] → complete column
matrix[row, :] → complete row
18. Slicing a 2D Array
A two-dimensional slice can select both rows and columns.
Syntax
array[row_start:row_stop, column_start:column_stop]
matrix = np.array([
[10, 20, 30, 40],
[50, 60, 70, 80],
[90, 100, 110, 120]
])
result = matrix[0:2, 1:3]
print(result)
Output:
[[20 30]
[60 70]]
19. Selecting Multiple Rows
matrix = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])
print(matrix[0:2, :])
Output:
[[10 20 30]
[40 50 60]]
20. Selecting Multiple Columns
print(matrix[:, 0:2])
Output:
[[10 20]
[40 50]
[70 80]]
21. 2D Slicing with Step
matrix = np.arange(1, 17).reshape(4, 4)
print(matrix[::2, ::2])
Output:
[[ 1 3]
[ 9 11]]
Here:
::2selects every second row.::2selects every second column.
22. Negative Indexing in 2D Arrays
matrix = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])
print(matrix[-1, -1])
print(matrix[-1, :])
print(matrix[:, -1])
Output:
90
[70 80 90]
[30 60 90]
Negative indexing is particularly useful when working with the last row or last column.
23. Boolean Indexing
Boolean indexing selects elements according to a Boolean condition.
numbers = np.array([10, 25, 30, 45, 50])
result = numbers > 30
print(result)
Output:
[False False False True True]
The Boolean array can then be used to select the matching values.
print(numbers[numbers > 30])
Output:
[45 50]
24. Filtering Data Using Conditions
Boolean indexing is extremely important in Data Science because it allows us to filter datasets.
scores = np.array([
45, 67, 82, 91, 56, 74, 39
])
passed = scores[scores >= 50]
print(passed)
Output:
[67 82 91 56 74]
Only scores greater than or equal to 50 are selected.
25. Combining Boolean Conditions
NumPy supports combining conditions using:
&for AND|for OR~for NOT
AND Condition
scores = np.array([
45, 55, 65, 75, 85, 95
])
result = scores[
(scores >= 60) & (scores <= 90)
]
print(result)
Output:
[65 75 85]
Use &, |, and ~ for
element-wise Boolean operations on NumPy arrays. Do not use
Python's and and or for this purpose.
26. OR Condition
scores = np.array([
35, 45, 55, 65, 75, 85
])
result = scores[
(scores < 40) | (scores > 80)
]
print(result)
Output:
[35 85]
27. NOT Condition
scores = np.array([
35, 45, 55, 65, 75
])
result = scores[~(scores < 50)]
print(result)
Output:
[55 65 75]
28. np.where() for Conditional Selection
np.where() can be used to find positions where a
condition is true or to select values based on a condition.
Finding Positions
numbers = np.array([10, 25, 30, 45, 50])
positions = np.where(numbers > 30)
print(positions)
The result identifies the indices where the condition is true.
Conditional Values
numbers = np.array([10, 25, 30, 45, 50])
result = np.where(
numbers >= 30,
"Pass",
"Fail"
)
print(result)
Output:
['Fail' 'Fail' 'Pass' 'Pass' 'Pass']
29. Fancy Indexing
Fancy indexing means selecting elements using an array or list of integer indices.
numbers = np.array([
10, 20, 30, 40, 50
])
indices = [0, 2, 4]
result = numbers[indices]
print(result)
Output:
[10 30 50]
This allows non-contiguous elements to be selected in a single operation.
30. Fancy Indexing in 2D Arrays
matrix = np.array([
[10, 20],
[30, 40],
[50, 60],
[70, 80]
])
rows = [0, 2, 3]
result = matrix[rows]
print(result)
Output:
[[10 20]
[50 60]
[70 80]]
The selected rows are 0, 2 and 3.
31. Selecting Specific 2D Coordinates
Integer arrays can be used to select corresponding row and column positions.
matrix = np.array([
[10, 20, 30],
[40, 50, 60],
[70, 80, 90]
])
rows = [0, 1, 2]
columns = [2, 1, 0]
result = matrix[rows, columns]
print(result)
Output:
[30 50 70]
The selected coordinates are:
(0, 2)
(1, 1)
(2, 0)
32. Indexing vs Slicing vs Boolean Indexing
| Technique | Purpose | Example |
|---|---|---|
| Indexing | Access a specific element. |
arr[2]
|
| Slicing | Select a continuous/rule-based range. |
arr[1:5]
|
| Boolean indexing | Select values satisfying a condition. |
arr[arr > 50]
|
| Fancy indexing | Select specified positions. |
arr[[0, 2, 4]]
|
33. Views and Copies
An important concept in NumPy is the difference between a view and a copy.
A view refers to the same underlying data, while a copy contains independent data.
Slice Example
numbers = np.array([10, 20, 30, 40, 50])
part = numbers[1:4]
part[0] = 999
print(numbers)
Output:
[ 10 999 30 40 50]
The original array changed because a basic slice generally returns a view.
34. Creating an Independent Copy
Use copy() when you want an independent array.
numbers = np.array([10, 20, 30, 40, 50])
part = numbers[1:4].copy()
part[0] = 999
print(numbers)
print(part)
Output:
[10 20 30 40 50]
[999 30 40]
Use .copy() when you intentionally need an
independent array and do not want changes to affect the
original data.
35. Boolean Mask
A Boolean mask is an array of True and
False values used to filter data.
temperatures = np.array([
18, 22, 27, 31, 35
])
mask = temperatures > 25
print(mask)
Output:
[False False True True True]
Applying the mask:
print(temperatures[mask])
Output:
[27 31 35]
36. Data Science Example — Filtering Student Marks
marks = np.array([
45, 78, 91, 56, 88, 39, 72
])
high_scores = marks[marks >= 75]
print(high_scores)
Output:
[78 91 88]
This is a basic example of filtering numerical observations based on a business or analytical rule.
37. Filtering a 2D Array
marks = np.array([
[78, 65, 91],
[55, 88, 72],
[92, 81, 69]
])
result = marks[marks >= 80]
print(result)
Output:
[91 88 92 81]
Boolean indexing returns the matching elements as a one-dimensional result.
38. Selecting Rows Using a Condition
Suppose each row represents a student and the columns represent different subjects.
marks = np.array([
[78, 82, 91],
[55, 60, 65],
[88, 92, 95],
[45, 51, 58]
])
row_condition = marks[:, 0] >= 70
selected = marks[row_condition]
print(selected)
Output:
[[78 82 91]
[88 92 95]]
Here, only rows where the first subject score is at least 70 are selected.
39. Selecting Rows Using Multiple Conditions
marks = np.array([
[78, 82, 91],
[55, 60, 65],
[88, 92, 95],
[45, 51, 58]
])
condition = (
(marks[:, 0] >= 70) &
(marks[:, 1] >= 80)
)
selected = marks[condition]
print(selected)
Output:
[[78 82 91]
[88 92 95]]
40. Conditional Selection from Columns
marks = np.array([
[78, 82, 91],
[55, 60, 65],
[88, 92, 95]
])
math_marks = marks[:, 0]
high_math = math_marks[math_marks >= 80]
print(high_math)
Output:
[88]
41. np.clip() — Restricting Values to a Range
np.clip() is useful when values must be constrained
within a specified minimum and maximum.
values = np.array([
10, 25, 50, 75, 100
])
result = np.clip(
values,
20,
80
)
print(result)
Output:
[20 25 50 75 80]
Values below 20 become 20, while values above 80 become 80.
42. np.nonzero()
np.nonzero() returns the indices of non-zero elements.
values = np.array([0, 5, 0, 8, 12])
positions = np.nonzero(values)
print(positions)
The returned indices identify the positions containing non-zero values.
43. np.argwhere()
np.argwhere() returns the indices of elements that
satisfy a condition.
values = np.array([10, 25, 30, 45, 50])
positions = np.argwhere(values > 30)
print(positions)
The result contains the positions where the condition is true.
44. Indexing & Slicing Cheatsheet
| Operation | Syntax | Purpose |
|---|---|---|
| Single element |
arr[2]
|
Access one element. |
| Last element |
arr[-1]
|
Access the final element. |
| Basic slice |
arr[1:5]
|
Select a range. |
| Every second value |
arr[::2]
|
Select with step 2. |
| Reverse |
arr[::-1]
|
Reverse an array. |
| 2D element |
arr[1, 2]
|
Select row 1, column 2. |
| Complete row |
arr[1, :]
|
Select one row. |
| Complete column |
arr[:, 1]
|
Select one column. |
| 2D slice |
arr[0:2, 1:3]
|
Select rows and columns. |
| Boolean filter |
arr[arr > 50]
|
Select values satisfying a condition. |
| Fancy indexing |
arr[[0, 2, 4]]
|
Select specified positions. |
45. NumPy Interview Questions
Q1. What is the difference between indexing and slicing?
View Answer
Indexing normally accesses a specific element, whereas slicing selects a range or structured portion of an array.
Q2. Does NumPy use zero-based indexing?
View Answer
Yes. The first element has index 0.
Q3. What does arr[::-1] do?
View Answer
It returns the elements in reverse order using a step of
-1.
Q4. How do you select the second column of a 2D NumPy array?
View Answer
Use arr[:, 1]. The colon selects all rows and
index 1 selects the second column.
Q5. What is Boolean indexing?
View Answer
Boolean indexing uses an array of Boolean values or a condition to select elements that satisfy a particular criterion.
Q6. Why are parentheses important when combining NumPy conditions?
View Answer
Each comparison should normally be enclosed in parentheses
when using element-wise operators such as
& and |, so that the
comparisons are evaluated as intended.
Q7. What is fancy indexing?
View Answer
Fancy indexing selects elements using arrays or lists of integer indices, allowing non-contiguous positions to be selected.
Q8. Why might you use copy() after slicing?
View Answer
Basic slices generally produce views. Using
copy() creates independent data so changes to
the new array do not modify the original.
46. Examination Questions
Multiple Choice Questions
Q1. What is the index of the first element of a NumPy array?
- 1
- -1
- 0
- None
Answer: C — 0
Q2. What is the output?
arr = np.array([10, 20, 30, 40, 50])
print(arr[1:4])
[10 20 30][20 30 40][20 30 40 50][10 20 30 40]
Answer: B — [20 30 40]
Q3. What does arr[-1] return?
- First element
- Second element
- Last element
- Array length
Answer: C — Last element
Q4. Which expression selects the second column of a 2D array?
arr[1, :]arr[:, 1]arr[1]arr[:, 2]
Answer: B — arr[:, 1]
Q5. What does the following expression select?
arr[arr > 50]
- All elements
- Elements less than 50
- Elements greater than 50
- Only element at index 50
Answer: C — Elements greater than 50
Q6. Which operator is used for element-wise AND between NumPy Boolean conditions?
and&&&AND
Answer: C — &
Short Answer Questions
- Explain zero-based indexing with an example.
- Explain negative indexing in NumPy.
-
Explain the syntax
start:stop:step. - How can you select an entire row from a 2D NumPy array?
- How can you select an entire column from a 2D NumPy array?
- What is Boolean indexing? Give an example.
- Differentiate between Boolean indexing and fancy indexing.
-
Why should parentheses be used around individual conditions
when using
&or|?
47. Practical Challenge
Build a NumPy Data Filter
Create a NumPy-based program that analyzes a collection of student marks.
- Create a 1D array containing at least 10 marks.
- Display the first, last, and third elements.
- Display the first five marks using slicing.
- Display every second mark.
- Display the marks in reverse order.
- Select all marks greater than or equal to 75.
- Select marks between 50 and 80.
-
Find the positions of marks greater than 90 using
np.where(). - Create a 2D array and display one complete row.
- Display one complete column.
- Extract a rectangular portion of the 2D array using slicing.
- Select specific rows using fancy indexing.
- Create a copy of a slice and demonstrate that modifying the copy does not modify the original.
48. Common Mistakes to Avoid
-
Forgetting zero-based indexing:
The first element is at index
0. -
Including the stop index:
In
arr[1:4], index 4 is excluded. -
Using
andinstead of&: Use element-wise Boolean operators for NumPy arrays. -
Forgetting parentheses:
Write
(arr > 10) & (arr < 50). -
Confusing rows and columns:
In
arr[row, column], the first index is the row. - Assuming slices are always independent: Basic slices generally return views.
-
Modifying a slice unintentionally:
Use
.copy()when an independent array is required.
49. Key Takeaways
- NumPy uses zero-based indexing.
- Negative indices access elements from the end of the array.
-
Basic slicing follows the pattern
start:stop:step. - The start position is included, while the stop position is normally excluded.
-
arr[::-1]reverses a one-dimensional array. -
2D elements can be accessed using
arr[row, column]. -
arr[row, :]selects a complete row. -
arr[:, column]selects a complete column. - Boolean indexing is used for conditional filtering.
-
&,|, and~are used for element-wise Boolean operations. -
np.where()can locate positions or select values based on a condition. - Fancy indexing selects specified positions using integer index arrays.
-
Basic slices generally return views, while
copy()creates independent data.
Indexing selects specific data, slicing selects a structured portion, and Boolean/fancy indexing lets you select data based on conditions or specified positions.