NumPy
Intermediate 14 min read NumPy

Indexing and Slicing

Selecting data without loops — and without accidents

Fancy indexing, slices and boolean masks select exactly the rows, columns and elements you want — and choosing view vs copy determines whether you silently mutate your data.

indexingslicingboolean maskfancy indexingview vs copy
Before we start

What you will learn

  • Slice with step and negative indices
  • Use boolean masks and integer arrays for selection
  • Explain view-vs-copy and avoid mutation traps
Introduction

What is this?

numpy selection comes in four forms: integer positions (arr[2]), slices (arr[1:5:2]), boolean masks (arr[arr > 0]), and fancy integer arrays (arr[[0, 2, 5]]). The catch: slices of basic indexing return views sharing memory; advanced indexing returns copies. Misreading that distinction is a classic production bug.

Motivation

Why do you need it?

  • Data extraction and subsetting happen constantly; loops are the slow way to do it.
  • Boolean masks are how outliers, missing values and category subsets are filtered.
  • View vs copy confusion silently corrupts data when you mutate a selection.
  • Previewing shapes of selections (arr[:, 0], arr[::2]) reads code faster.
Think about it

Mental model

Imagine

Highlighting a page in a book vs taking a photo of a page

Think of

View (basic) vs copy (fancy indexing)

Highlighting the book marks the same shared paper — edit the highlight, edit the book (view). A photo is independent — change the photo, the book is untouched (copy).

Mechanics

How it works

  • arr[i], arr[i, j] pick elements; arr[1:4] and arr[::-1] slice sequences with steps.
  • Boolean mask: arr[mask] where mask has shape == arr shape, keeping True positions.
  • Fancy indexing with an array of positions returns a copy of the selected elements.
  • Basic indexing (slices, single ints) returns a view — logically the same buffer.
  • Transposing and ravel also produce views; reshape may too.

What each selection returns.

Basic index
Boolean mask
Fancy index
Mutation?
Hands-on

Examples

Selection styles side by side

Selection styles side by side
import numpy as np
a = np.arange(20.0)
mask = (a > 8) & (a < 13)
print(a[mask]) # boolean selection → [9,10,11,12]
print(a[a % 4 == 0]) # every 4th value
print(a[::3]) # step slice → view
rows = np.arange(20).reshape(5, 4)
print(rows[2]) # 3rd row (view)
print(rows[:, 1]) # 2nd column (view)

Mask and step selections pull exactly the intended values in one line. The 1D step slice is a view — mutate it and `a` changes — so know which kind of array you're manipulating before assignment.

Real world

In production

  • A monitoring job grabs `latency[latency > p99]` to study the slowest 1% only.
  • An A/B analysis slices control/treatment via a boolean assignment mask on a cohort column.
  • A feature pipeline samples `arr[::50]` for quick previews before full processing.
Guidelines

Best practices

  • Prefer boolean masks over loops for filtering.
  • If you will mutate a selection, force a copy: selected.copy().
  • Use .copy() wherever the semantics could confuse the next maintainer.
Watch out

Common mistakes

  • Assigning to a slice and discovering the parent changed too (view).
  • Believing fancy indexing returns a view — it returns a copy, breaking in-place edits.
  • Forgetting mask shape equality → IndexError or silent misalignment.
When things break

Debugging tips

  • Identify view-vs-copy: assign arr2 = arr[:3]; arr2[0]=99; check arr[0].
  • For wrong selection counts, print mask.sum() to confirm how many elements matched.
  • When mutation 'doesn't stick', you likely have a fancy-indexed copy, not a view.
Interviews

Interview checkpoint

Practice

Hands-on lab

Indexing Playground
25 min · intermediate
In progress
Objectives
  • Practice slice, mask and fancy selection
  • Find the p99+1% values with masks
  • Prove view vs copy behavior

Indexing Playground

25 min · intermediate

0/5 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/2
1

arr[arr > 3] is which kind of selection?

2

Mutating the result of arr[1:5] also changes arr.

Go deeper

Official documentation