Complete Guide to NumPy Array Indexing: From Basic Indexing to Advanced Selection

 



Complete Guide to NumPy Array Indexing: From Basic Indexing to Advanced Selection

Habbit2Code – Online Coding Classes

When working with NumPy, creating an array is only the beginning. The real power of NumPy appears when we can efficiently select, extract, modify, and filter specific elements from an array.

This process is called indexing.

In normal Python lists, we commonly use expressions such as:

numbers[2]
numbers[1:5]

NumPy extends this idea much further. We can index individual elements, entire rows or columns, rectangular portions of multidimensional arrays, selected elements using integer arrays, and elements satisfying conditions using Boolean indexing.

This guide explains NumPy indexing from beginner to advanced level.


What You Will Learn

By the end of this article, you will understand:

  • Single-element indexing

  • Positive and negative indexing

  • Multidimensional indexing

  • Row and column selection

  • Slicing

  • Striding

  • Reversing arrays

  • Views versus copies

  • Ellipsis (...)

  • np.newaxis

  • Integer-array indexing

  • Advanced indexing

  • Boolean indexing

  • Combining indexing techniques

  • Indexing structured arrays

  • Flat-array indexing

  • Assigning values using indexing

  • Common indexing mistakes

  • Practical and interview-oriented examples


1. What Is NumPy Indexing?

NumPy indexing means selecting one or more elements from an array using square brackets:

array[index]

For example:

import numpy as np

numbers = np.array([10, 20, 30, 40, 50])

print(numbers[2])

Output:

30

The index starts from 0.

Index positions

Array values:    10    20    30    40    50
                 |     |     |     |     |
Index:           0     1     2     3     4

Therefore:

numbers[0]   # 10
numbers[2]   # 30
numbers[4]   # 50

NumPy follows Python's zero-based indexing convention. (NumPy)


2. Positive Indexing

Positive indexing starts from the beginning of the array.

import numpy as np

marks = np.array([72, 85, 91, 66, 78])

print(marks[0])
print(marks[3])

Output:

72
66

The general rule is:

First element  → index 0
Second element → index 1
Third element  → index 2
...

3. Negative Indexing

Negative indexing allows us to access elements from the end.

numbers = np.array([10, 20, 30, 40, 50])

print(numbers[-1])
print(numbers[-2])

Output:

50
40

Visual representation:

Values:       10    20    30    40    50
Positive:      0     1     2     3     4
Negative:     -5    -4    -3    -2    -1

This is particularly useful when you want the last few elements without calculating their positive positions.


4. Indexing Multidimensional Arrays

NumPy becomes especially powerful when working with two-dimensional or multidimensional arrays.

Consider:

import numpy as np

matrix = np.array([
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
])

We can visualize it as:

             Column
              0    1    2

Row 0       [10   20   30]
Row 1       [40   50   60]
Row 2       [70   80   90]

To access 50:

print(matrix[1, 1])

Output:

50

The first index identifies the row and the second identifies the column.

matrix[row, column]

For example:

matrix[2, 0]

returns:

70

5. Why array[row, column] Is Preferred

You may also see:

matrix[1][1]

This produces the same value:

50

However, NumPy's multidimensional indexing is naturally expressed as:

matrix[1, 1]

rather than:

matrix[1][1]

The first form directly describes the multidimensional location and avoids creating an intermediate indexed result. (NumPy)


6. Selecting an Entire Row

Suppose:

matrix = np.array([
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
])

To select the second row:

print(matrix[1])

Output:

[40 50 60]

The reason is simple:

matrix[1]

means:

Select row 1 and leave the remaining dimension unspecified.

You can think of it as:

matrix[1, :]

Both select the complete row.


7. Selecting an Entire Column

To select the second column:

print(matrix[:, 1])

Output:

[20 50 80]

Here:

:  → select all rows
1  → select column 1

Therefore:

matrix[:, 1]

means:

Select every row from column 1.


8. The Colon : in NumPy Indexing

The colon is one of the most important tools in NumPy indexing.

Basic slicing follows:

start : stop : step

For example:

numbers = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

print(numbers[2:7])

Output:

[2 3 4 5 6]

Remember:

The stop index is excluded.

So:

2:7

means:

2, 3, 4, 5, 6

9. Understanding start:stop:step

Consider:

numbers[1:9:2]

This means:

start = 1
stop  = 9
step  = 2

Therefore:

1 → 3 → 5 → 7

Output:

[1 3 5 7]

A useful way to remember it:

array[start : stop : step]
       ↓       ↓      ↓
     begin   end    jump

10. Omitting Slice Components

NumPy allows us to omit one or more parts of the slice.

From the beginning

numbers[:5]

means:

Start from index 0 and stop before index 5.

Output:

[0 1 2 3 4]

Until the end

numbers[5:]

Output:

[5 6 7 8 9]

Every second element

numbers[::2]

Output:

[0 2 4 6 8]

Every third element

numbers[::3]

Output:

[0 3 6 9]

11. Reversing an Array

A negative step allows us to move backwards.

numbers = np.array([10, 20, 30, 40, 50])

print(numbers[::-1])

Output:

[50 40 30 20 10]

The expression:

[::-1]

means:

Start from the end and move backwards one position at a time.

This is one of the most useful NumPy slicing techniques.


12. Negative Slice Indices

Negative indices can also be used in slices.

numbers = np.array([10, 20, 30, 40, 50])

print(numbers[-4:-1])

Output:

[20 30 40]

The negative positions are:

Value:       10    20    30    40    50
Index:        0     1     2     3     4
Negative:    -5    -4    -3    -2    -1

13. Slicing a 2-D Array

Consider:

matrix = np.array([
    [1,  2,  3,  4],
    [5,  6,  7,  8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
])

To select the first two rows:

print(matrix[:2])

Output:

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

To select columns 1 and 2:

print(matrix[:, 1:3])

Output:

[[ 2  3]
 [ 6  7]
 [10 11]
 [14 15]]

14. Selecting a Rectangular Region

We can combine row and column slicing.

print(matrix[1:3, 1:3])

Output:

[[ 6  7]
 [10 11]]

Diagram:

Original matrix

       0   1   2   3
    +---+---+---+---+
 0  | 1 | 2 | 3 | 4 |
    +---+---+---+---+
 1  | 5 | 6 | 7 | 8 |
    +---+---+---+---+
 2  | 9 |10 |11 |12 |
    +---+---+---+---+
 3  |13 |14 |15 |16 |
    +---+---+---+---+

matrix[1:3, 1:3]

       1   2
    +---+---+
 1  | 6 | 7 |
    +---+---+
 2  |10 |11 |
    +---+---+

This technique is extremely useful in image processing, numerical computing, and machine learning.


15. NumPy Slicing Usually Produces a View

One of the most important differences between NumPy arrays and ordinary Python sequences is the concept of a view.

Consider:

numbers = np.array([10, 20, 30, 40, 50])

part = numbers[1:4]

part[0] = 999

print(numbers)

Output:

[ 10 999  30  40  50]

Why did the original array change?

Because basic slicing generally produces a view of the original array rather than an independent copy. (NumPy)

Think of it this way:

Original Array
      |
      |---- View
      |
      +---- Same underlying data

If you need an independent array:

part = numbers[1:4].copy()

Now changes to part will not modify numbers.


16. Why Views Matter

Views are useful because they can avoid unnecessary data copying.

This can improve memory efficiency.

However, they can also cause unexpected modifications.

For example:

data = np.array([1, 2, 3, 4, 5])

subset = data[1:4]

subset[:] = 100

print(data)

Output:

[  1 100 100 100   5]

If you do not want this behaviour:

subset = data[1:4].copy()

Interview Point

Basic slicing generally returns a view. Advanced indexing returns a copy.

This distinction is extremely important when writing efficient NumPy programs. (NumPy)


17. The Ellipsis ...

For arrays with many dimensions, writing every : can become inconvenient.

NumPy provides:

...

called Ellipsis.

For example:

x[..., 0]

can represent:

x[:, :, 0]

when the array has three dimensions. (NumPy)

The idea is:

... → fill in the required number of :

For example:

x[..., 0]

can be interpreted as:

all dimensions before the final dimension
+
index 0 of the final dimension

This becomes especially useful with high-dimensional arrays.


18. What Is np.newaxis?

np.newaxis is used to insert a new dimension into an array.

Consider:

x = np.array([1, 2, 3, 4])

Its shape is:

x.shape

Output:

(4,)

Now:

y = x[:, np.newaxis]

The shape becomes:

(4, 1)

Diagram:

Original:

[1 2 3 4]

Shape = (4,)


After np.newaxis:

[[1]
 [2]
 [3]
 [4]]

Shape = (4, 1)

np.newaxis is an alias for None. (NumPy)

Therefore:

x[:, np.newaxis]

and:

x[:, None]

produce the same shape.


19. Practical Use of np.newaxis

np.newaxis is particularly useful when preparing arrays for broadcasting.

Example:

x = np.arange(5)

result = x[:, np.newaxis] + x[np.newaxis, :]

print(result)

Output:

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

Instead of manually constructing a two-dimensional matrix, we changed the shapes of two one-dimensional arrays and allowed NumPy broadcasting to perform the operation. (NumPy)


20. Basic Indexing vs Advanced Indexing

NumPy indexing can broadly be understood through two major categories:

                    NumPy Indexing
                          |
             +------------+------------+
             |                         |
       Basic Indexing            Advanced Indexing
             |                         |
      Integer / Slice          Integer Arrays / Boolean
             |                         |
          Views                       Copies

This distinction is one of the most important concepts to understand.


21. What Is Advanced Indexing?

Advanced indexing occurs when NumPy receives indexing objects such as integer arrays or Boolean arrays.

For example:

numbers = np.array([10, 20, 30, 40, 50])

indices = np.array([0, 2, 4])

print(numbers[indices])

Output:

[10 30 50]

We are no longer asking for one continuous slice.

Instead, we are saying:

Give me elements at positions 0, 2, and 4.

Advanced indexing produces a copy rather than a basic-indexing view. (NumPy)


22. Integer Array Indexing

Integer-array indexing allows us to select arbitrary positions.

numbers = np.array([10, 20, 30, 40, 50, 60])

positions = np.array([4, 1, 5])

print(numbers[positions])

Output:

[50 20 60]

Notice that the output follows the order of the index array.

Index array:
[4, 1, 5]
 |  |  |
 ↓  ↓  ↓
50 20 60

The selected values do not need to be consecutive.


23. Repeated Indices

Integer indexing also allows repeated positions.

numbers = np.array([10, 20, 30, 40])

print(numbers[[2, 2, 0, 3]])

Output:

[30 30 10 40]

The same element can therefore be selected multiple times.


24. Out-of-Bounds Integer Indexing

Index values must be valid.

For example:

numbers = np.array([10, 20, 30])

print(numbers[[0, 3]])

This raises an IndexError because index 3 does not exist.

Valid indices are:

0
1
2

but not:

3

25. Advanced Indexing in 2-D Arrays

Consider:

matrix = np.array([
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
])

Suppose we want:

10
50
70

We can specify row and column indices:

rows = np.array([0, 1, 2])
columns = np.array([0, 1, 0])

print(matrix[rows, columns])

Output:

[10 50 70]

NumPy pairs the indices:

(0, 0) → 10
(1, 1) → 50
(2, 0) → 70

This is very different from ordinary row/column slicing.


26. Broadcasting of Index Arrays

When multiple integer index arrays are used, NumPy attempts to broadcast them to compatible shapes.

For example:

x = np.arange(35).reshape(5, 7)

rows = np.array([0, 2, 4])
columns = np.array([0, 1, 2])

print(x[rows, columns])

The pairs are:

(0,0)
(2,1)
(4,2)

So the result contains those three locations.

If the index arrays cannot be broadcast to compatible shapes, NumPy raises an IndexError. (NumPy)


27. Selecting Rows with Integer Arrays

Integer indexing can also select complete rows.

data = np.arange(20).reshape(4, 5)

rows = np.array([0, 2, 3])

print(data[rows])

This selects:

Row 0
Row 2
Row 3

The result contains complete rows.

This is useful when a machine-learning dataset contains selected training samples or records.


28. Selecting Multiple Rows and Columns

Suppose:

data = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [10, 11, 12]
])

We want rows:

0 and 3

and columns:

0 and 2

We can use:

rows = np.array([0, 3])
columns = np.array([0, 2])

But:

data[rows, columns]

does not produce the complete 2 × 2 combination.

Instead, it pairs the indices:

(0,0)
(3,2)

giving:

[1, 12]

This is a common source of confusion.


29. Using np.ix_() for Row-Column Combinations

If we actually want all combinations:

Rows:    0, 3
Columns: 0, 2

we can use:

rows = np.array([0, 3])
columns = np.array([0, 2])

result = data[np.ix_(rows, columns)]

print(result)

Output:

[[ 1  3]
 [10 12]]

The selected positions are:

(0,0)   (0,2)
(3,0)   (3,2)

np.ix_() is particularly useful when we want combinations rather than pairwise matching of advanced indices. (NumPy)


30. Boolean Indexing

Boolean indexing is one of the most useful NumPy features.

Instead of specifying positions manually, we specify a condition.

Example:

numbers = np.array([10, 15, 20, 25, 30])

print(numbers > 20)

Output:

[False False False  True  True]

This Boolean array can itself be used for indexing:

print(numbers[numbers > 20])

Output:

[25 30]

31. How Boolean Indexing Works

Think of Boolean indexing as a filter:

Values:     10   15   20   25   30
Condition:  F    F    F    T    T
                         ↓    ↓
Result:                  25   30

This makes Boolean indexing extremely useful for data analysis.


32. Filtering Values

Suppose we have student marks:

marks = np.array([45, 78, 91, 34, 67, 88])

Select marks greater than or equal to 70:

passed = marks[marks >= 70]

print(passed)

Output:

[78 91 88]

No explicit Python loop is required.


33. Selecting Negative Values

numbers = np.array([10, -5, 20, -8, 15])

negative = numbers[numbers < 0]

print(negative)

Output:

[-5 -8]

34. Modifying Elements Using Boolean Indexing

Boolean indexing is not limited to reading values.

We can also modify them.

numbers = np.array([10, -5, 20, -8, 15])

numbers[numbers < 0] = 0

print(numbers)

Output:

[10  0 20  0 15]

This is much more concise than writing a loop.


35. Combining Conditions

We can combine multiple conditions.

For example, select values between 20 and 50:

numbers = np.array([10, 20, 25, 40, 55, 70])

result = numbers[(numbers >= 20) & (numbers <= 50)]

print(result)

Output:

[20 25 40]

For NumPy Boolean expressions, use operators such as:

&   → AND
|   → OR
~   → NOT

Use parentheses around individual conditions.

Correct:

(numbers > 10) & (numbers < 50)

Avoid:

numbers > 10 & numbers < 50

because operator precedence can produce unexpected results.


36. Removing NaN Values

Boolean indexing is especially useful for handling missing numerical values.

Consider:

data = np.array([
    10.0,
    np.nan,
    20.0,
    np.nan,
    30.0
])

We can select values that are not NaN:

clean = data[~np.isnan(data)]

print(clean)

Output:

[10. 20. 30.]

The NumPy documentation uses this technique as a practical Boolean-indexing example. (NumPy)


37. Boolean Indexing on 2-D Arrays

Consider:

matrix = np.array([
    [10, 20, 30],
    [40, 50, 60],
    [70, 80, 90]
])

To select every value greater than 50:

result = matrix[matrix > 50]

print(result)

Output:

[60 70 80 90]

Notice that the result is one-dimensional.

A Boolean mask can therefore extract all elements for which the corresponding condition is True. (NumPy)


38. Boolean Masks

A Boolean condition creates what is often called a mask.

mask = matrix > 50

The mask looks like:

False False False
False False True
True  True  True

Then:

matrix[mask]

extracts the corresponding values.

Conceptually:

Original Array
      |
      v
Apply condition
      |
      v
Boolean Mask
      |
      v
Select True positions
      |
      v
Filtered Array

This pattern is fundamental in NumPy-based data science.


39. Combining Basic and Advanced Indexing

NumPy also allows different indexing techniques to be combined.

For example:

data = np.arange(35).reshape(5, 7)

rows = np.array([0, 2, 4])

result = data[rows, 1:3]

print(result)

Output:

[[ 1  2]
 [15 16]
 [29 30]]

Here:

rows

performs advanced indexing, while:

1:3

performs slicing.

The resulting dimensions depend on how the advanced and basic indexing components are arranged. (NumPy)


40. Field Access in Structured Arrays

NumPy also supports structured arrays, where each element can contain named fields.

Example:

students = np.array([
    (101, 85.5),
    (102, 91.0),
    (103, 78.5)
], dtype=[
    ('roll', 'i4'),
    ('marks', 'f8')
])

Now we can access the marks field:

print(students['marks'])

Output:

[85.5 91.  78.5]

Similarly:

print(students['roll'])

returns:

[101 102 103]

Field indexing provides a convenient way to work with named components of structured arrays. (NumPy)


41. Flat Indexing with x.flat

NumPy arrays can also be viewed as a one-dimensional sequence through:

x.flat

Consider:

x = np.array([
    [10, 20, 30],
    [40, 50, 60]
])

Using:

print(x.flat[4])

gives:

50

The array is traversed in C-style order, where the final dimension changes fastest. (NumPy)

Conceptually:

2-D array:

10  20  30
40  50  60

Flat view:

10 → 20 → 30 → 40 → 50 → 60

42. Assigning Values Through Indexing

Indexing is not only for retrieving data.

We can use it to modify arrays.

numbers = np.arange(10)

numbers[2:5] = 100

print(numbers)

Output:

[  0   1 100 100 100   5   6   7   8   9]

43. Assigning Different Values

We can also assign an array of matching size.

numbers = np.arange(10)

numbers[2:5] = np.array([100, 200, 300])

print(numbers)

Output:

[  0   1 100 200 300   5   6   7   8   9]

The assigned values must have a shape compatible with the selected region. NumPy can use broadcasting where appropriate. (NumPy)


44. Data Type and Assignment

Be careful when assigning values with a different data type.

For example:

numbers = np.array([1, 2, 3])

numbers[0] = 1.8

print(numbers)

Since the array contains integers, the assigned floating-point value is converted according to the array's data type.

Output:

[1 2 3]

The original array's data type controls how assigned values are represented.


45. Basic Indexing vs Advanced Indexing: The Critical Difference

This is one of the most important concepts for interviews.

FeatureBasic IndexingAdvanced Indexing
Typical syntaxa[1:5]a[[1,3,4]]
Integer indexYesYes, when arrays/sequences are involved
SliceYesNo, by itself
Boolean arrayNoYes
Integer arrayNoYes
Usually returnsViewCopy
Can modify original through returned object?Generally yesGenerally no

NumPy's documentation explicitly distinguishes basic slicing, which returns views, from advanced indexing, which returns copies. (NumPy)


46. A Complete Indexing Decision Guide

When you see an indexing expression, ask:

What is inside []?
        |
        +---- Single integer?
        |        ↓
        |    Single element
        |
        +---- Slice?
        |        ↓
        |    Basic slicing / View
        |
        +---- Integer array?
        |        ↓
        |    Advanced indexing / Copy
        |
        +---- Boolean array?
        |        ↓
        |    Boolean indexing / Copy
        |
        +---- ... ?
        |        ↓
        |    Fill unspecified dimensions
        |
        +---- np.newaxis?
                 ↓
            Add a dimension

This mental model makes NumPy indexing much easier to understand.


47. Real-World Example: Student Marks

Suppose:

marks = np.array([
    [78, 85, 91],
    [62, 74, 81],
    [90, 88, 95],
    [55, 68, 72]
])

Rows represent students and columns represent subjects.

Select the first student

marks[0]

Select marks for the second subject

marks[:, 1]

Select students with marks greater than 80 anywhere

marks[marks > 80]

Replace marks below 60 with zero

marks[marks < 60] = 0

This demonstrates how indexing becomes a practical data-processing tool rather than merely a way of retrieving individual values.


48. Real-World Example: Image Processing

Images can be represented as NumPy arrays.

A grayscale image can be represented approximately as:

Height × Width

For example:

image.shape

might return:

(720, 1280)

A color image might have:

Height × Width × Channels

such as:

(720, 1280, 3)

where the three channels commonly represent RGB components.

We can therefore use indexing to:

  • select a row of pixels

  • select a column

  • crop an image

  • access a specific pixel

  • modify a region

  • select pixels satisfying a condition

For example:

crop = image[100:300, 200:500]

This extracts a rectangular region.


49. Common NumPy Indexing Mistakes

Mistake 1: Forgetting zero-based indexing

Wrong assumption:

First element = 1

Correct:

First element = 0

Mistake 2: Forgetting that stop is excluded

x[2:5]

does not include index 5.

It selects:

2, 3, 4

Mistake 3: Confusing rows and columns

For:

x[row, column]

the first value is the row and the second is the column.


Mistake 4: Assuming slicing creates a copy

This can cause unexpected modifications.

If you need an independent array:

subset = x[1:5].copy()

Mistake 5: Confusing advanced indexing with slicing

These are different:

x[1:4]

and:

x[[1, 2, 3]]

The first is basic slicing; the second is advanced indexing.


Mistake 6: Forgetting parentheses in Boolean conditions

Use:

x[(x > 10) & (x < 50)]

rather than relying on Python operator precedence.


Mistake 7: Expecting paired advanced indices to create a grid

For:

x[[0, 1], [1, 2]]

NumPy selects:

(0,1)
(1,2)

not every combination.

For combinations, consider:

np.ix_(rows, columns)

50. Performance Tip: Prefer Slicing When Possible

Suppose these two expressions produce the same values:

x[1:3]

and:

x[[1, 2]]

They are not equivalent internally.

The slice is basic indexing and generally returns a view, whereas the integer-array expression uses advanced indexing and returns a copy.

Therefore, when a simple slice can express the selection, it is often preferable from a memory-efficiency perspective. (NumPy)


51. Important Interview Questions

Q1. What is NumPy indexing?

It is the mechanism used to select or modify elements of an ndarray using expressions inside square brackets.

Q2. Does NumPy use zero-based indexing?

Yes.

Q3. Can NumPy use negative indices?

Yes.

Q4. What does : mean?

It represents a slice and can mean selecting an entire dimension when used alone.

Q5. What does array[:, 2] mean?

Select column 2 from every row.

Q6. What does array[2, :] mean?

Select row 2 and all columns.

Q7. Does basic slicing return a copy?

Generally, no. It returns a view.

Q8. Does advanced indexing return a copy?

Yes.

Q9. What is Boolean indexing?

Selecting array elements using a Boolean mask.

Q10. What is np.newaxis used for?

It inserts a new dimension into an array.

Q11. What is ...?

Ellipsis, which represents unspecified dimensions in an indexing expression.

Q12. What is np.ix_() useful for?

It helps create broadcastable index arrays for selecting combinations of rows and columns.


52. Quick Reference Table

OperationExample
First elementx[0]
Last elementx[-1]
Element at row 1, column 2x[1, 2]
First three elementsx[:3]
Elements from index 3x[3:]
Every second elementx[::2]
Reverse arrayx[::-1]
Complete rowx[1, :]
Complete columnx[:, 1]
Rectangular sectionx[1:3, 2:4]
Integer-array selectionx[[1, 3, 4]]
Boolean selectionx[x > 50]
Add dimensionx[:, np.newaxis]
Ellipsisx[..., 0]
Independent slicex[1:5].copy()
Row/column combinationsx[np.ix_(rows, cols)]
Flat indexingx.flat[5]

53. Self-Try Exercises

Try solving these without immediately looking at the answers.

Exercise 1: Basic Indexing

Create:

numbers = np.array([12, 24, 36, 48, 60, 72, 84])

Find:

  1. The first element

  2. The last element

  3. The third element

  4. The second-last element


Exercise 2: Slicing

Using:

numbers = np.arange(1, 21)

Write NumPy expressions to obtain:

  1. The first five numbers

  2. Numbers from 6 to 15

  3. Every second number

  4. Every third number

  5. The array in reverse order


Exercise 3: Matrix Indexing

Create:

matrix = np.arange(1, 26).reshape(5, 5)

Find:

  1. The center element

  2. The first row

  3. The last row

  4. The first column

  5. The last column

  6. The middle 3 × 3 section


Exercise 4: Boolean Indexing

Given:

marks = np.array([45, 78, 92, 61, 38, 85, 73, 55])

Write expressions to:

  1. Select marks greater than 70

  2. Select marks below 50

  3. Select marks between 50 and 80

  4. Replace marks below 40 with 0


Exercise 5: Advanced Indexing

Given:

data = np.array([
    [10, 20, 30, 40],
    [50, 60, 70, 80],
    [90, 100, 110, 120],
    [130, 140, 150, 160]
])

Use advanced indexing to:

  1. Select values at (0,0), (1,2), (3,1)

  2. Select rows 0 and 3

  3. Select rows 0 and 3 and columns 0 and 2 as all combinations using np.ix_()


54. Challenge Problem

Consider a student dataset:

students = np.array([
    [101, 78, 85, 91],
    [102, 45, 66, 72],
    [103, 92, 95, 89],
    [104, 55, 61, 64],
    [105, 88, 90, 94]
])

The columns represent:

Student ID | Subject 1 | Subject 2 | Subject 3

Write NumPy expressions to:

  1. Extract all student IDs.

  2. Extract marks of Subject 2.

  3. Find all marks greater than 90.

  4. Replace marks below 60 with 0.

  5. Select students whose Subject 1 marks are greater than 80.

  6. Select rows 0, 2, and 4 using integer-array indexing.

  7. Extract Subject 1 and Subject 3 for students 0, 2, and 4.

This exercise combines basic indexing, slicing, Boolean indexing, and advanced indexing.


55. Key Takeaways

NumPy indexing is much more than retrieving a single element.

The most important concepts to remember are:

x[i]

Select one element.

x[i, j]

Select an element from a multidimensional array.

x[start:stop:step]

Perform basic slicing.

x[rows, columns]

Use multidimensional indexing.

x[index_array]

Perform integer-array advanced indexing.

x[x > value]

Perform Boolean filtering.

x[:, np.newaxis]

Add a dimension.

x[..., 0]

Use Ellipsis to simplify multidimensional indexing.

x[1:5].copy()

Create an independent copy when required.

The single most important distinction to remember is:

Basic slicing
     ↓
Usually a VIEW

Advanced indexing
     ↓
COPY

Understanding this difference helps you write NumPy programs that are not only correct but also more memory-conscious and easier to reason about. (NumPy)


Conclusion

NumPy indexing provides a compact and powerful way to work with numerical data. Instead of writing lengthy loops, we can select rows, columns, regions, arbitrary elements, or conditionally filtered values using concise expressions.

For beginners, start with:

x[index]
x[start:stop]
x[row, column]
x[:, column]

Then progress to:

x[index_array]
x[boolean_mask]

Finally, explore:

np.newaxis
...
np.ix_()

and combinations of basic and advanced indexing.

Once these concepts become familiar, many NumPy operations that initially appear complicated become straightforward array-selection problems.

Next Step: Practice the five exercises above and then try implementing the challenge problem without using explicit for loops.


Comments