NumPy Pandas StudyGuide
NumPy Pandas StudyGuide
■ Table of Contents
PART 1 — NumPy
1.1 Python Array vs NumPy Array
1.2 Why NumPy is Memory Efficient
1.3 Applications and Uses
1.4 Creating NumPy Arrays (all types)
1.5 Vectorization & Broadcasting Intro
1.6 Data Types & Type Casting
1.7 Shapes & Reshaping
1.8 Arithmetic & Data-Type-Changing Operations
1.9 Conditional Operations
1.10 Universal Functions (ufuncs)
1.11 Indexing & Slicing
1.12 Multidimensional Slicing
1.13 Splitting Arrays
1.14 Broadcasting (deep dive)
1.15 Concatenation & Stacking
1.16 Aggregation
1.17 Masking & Boolean Indexing
1.18 Matrix Transpose
1.19 View vs Copy
1.20 Handling Missing Values
PART 2 — Pandas
2.1 Why Pandas?
2.2 Series — Creation, Indexing, Slicing, Modification, Sorting
2.3 Conditional Indexing in Series
2.4 DataFrames — Creation & Structure
2.5 loc & iloc
2.6 Broadcasting in DataFrames
2.7 Lambda Functions
2.8 Renaming Columns & Index
2.9 Dropping Rows/Columns
2.10 Importing Files (CSV, Excel, JSON)
2.11 Cleaning Data
2.12 Handling Duplicates
2.13 Date Reading & Formatting
2.14 Advanced Broadcasting in Pandas
Page 2
NumPy & Pandas — Advanced Study Guide
PART 1 — NumPy
Concept & Logic: A Python list is a collection of arbitrary Python objects, each carrying its own type metadata and
reference pointer (~28 bytes overhead per element). A NumPy array stores homogeneous raw binary values in a
contiguous block of memory, making element access O(1) with near-zero overhead.
Key Differences
Feature Python List NumPy Array
Size in memory ~56 bytes + 8 per int ~96 bytes + 8 per int (fixed)
import numpy as np
# Python list
py_list = [1, 2, 3, 4, 5]
# Check type
print(type(py_list)) # <class 'list'>
print(type(np_arr)) # <class '[Link]'>
# Memory comparison
import sys
print([Link](py_list)) # ~104 bytes for 5-element list
print(np_arr.nbytes) # 40 bytes (5 x 8-byte int64)
Q1. Create a Python list [10,20,30] and a NumPy array from it. Print the type and memory size of each.
Q2. What does [Link]([1,2,'three']) produce? Why? What dtype does it get?
Q1. Write a function that takes a Python list of floats, converts it to a NumPy array, and returns the ratio of Python list
size to NumPy array byte size.
Page 3
NumPy & Pandas — Advanced Study Guide
Q2. Explain why np_arr[0] is faster than py_list[0] at the hardware level.
Q1. Benchmark element-wise squaring for sizes 10^3, 10^5, 10^7 using both a list comprehension and NumPy. Plot the
results and explain the crossover point.
Q2. Describe how Python's garbage collector interacts with NumPy's memory model. When does NumPy free memory?
Page 4
NumPy & Pandas — Advanced Study Guide
Concept & Logic: NumPy achieves efficiency through: (1) Homogeneous dtype — each element is exactly
[Link] bytes, no Python object wrapper. (2) Contiguous memory — elements sit side-by-side so the CPU
cache can prefetch them. (3) Strides — a compact integer tuple tells NumPy how many bytes to jump per
dimension, enabling views (reshapes, transposes) without copying data.
import numpy as np
print([Link]) # int32
print([Link]) # 4 (bytes per element)
print([Link]) # 24 (6 * 4)
print([Link]) # (4,) — move 4 bytes to get next element
Q1. Create a 1-D array of 100 zeros with dtype int16. Print its nbytes and compare with int64.
Q2. What are strides? Print the strides of a (3,4) array of float32.
Q1. Create a 2-D array and take a slice (every other column). Show that the slice shares memory with the original using
np.shares_memory().
Q2. Why does changing dtype from float64 to float16 reduce memory 4x? What precision trade-off occurs?
Q1. Manually compute the memory address of element [i,j] in a (M,N) int32 array given its base address and strides.
Write a Python function that validates this.
Q2. Explain how [Link].stride_tricks.as_strided() can create a sliding-window view of a 1-D array. Implement it and
discuss the risks.
Page 5
NumPy & Pandas — Advanced Study Guide
Concept & Logic: NumPy is the backbone of the entire Python scientific stack. It powers: machine learning
(feature matrices in sklearn/TensorFlow), image processing (images as pixel arrays), signal processing (FFT),
financial modelling (vectorised price calculations), physics simulations, and genomics.
Q1. Use NumPy to create a (224, 224, 3) random uint8 array representing a fake RGB image.
Q2. Use [Link]() to compute the Euclidean distance between two 3-D points.
Q1. Simulate rolling two dice 100,000 times using [Link] and compute the probability distribution of their sum.
Q2. Normalise pixel values of a (H,W,3) image array to the range [0,1] in one line.
Q1. Implement a Monte Carlo estimation of pi using NumPy random points in a unit square. How many samples do you
need for 4 significant figures?
Q2. Solve the least-squares regression y = Xβ for a 1000×10 feature matrix X using [Link]. Discuss numerical
stability.
Page 6
NumPy & Pandas — Advanced Study Guide
Concept & Logic: NumPy provides a rich set of constructors. Knowing which one to reach for saves you from
explicit loops. Choose from: literal conversion, range-based, fill-based (zeros/ones/full), identity, random, and
linspace/logspace.
import numpy as np
# ■■ Range-based ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
r1 = [Link](0, 10, 2) # [0 2 4 6 8] (start, stop, step)
r2 = [Link](0, 1, 5) # [0. 0.25 0.5 0.75 1. ] (5 points incl ends)
r3 = [Link](0, 2, 3) # [ 1. 10. 100.] (log scale)
# ■■ Fill-based ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
z = [Link]((3, 4)) # 3×4 zeros float64
o = [Link]((2, 3), dtype=int) # 2×3 ones int64
f = [Link]((2, 2), 7.0) # 2×2 filled with 7.0
e = [Link]((3, 3)) # uninitialised (fast!)
# ■■ Random ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
rng = [Link].default_rng(42) # reproducible seed (new API)
u = [Link]((3, 3)) # uniform [0,1)
n = [Link](0, 1, (3, 3)) # standard normal
i = [Link](0, 10, (3,)) # random ints
# ■■ Special ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
flat = [Link](lambda i,j: i+j, (3,3), dtype=int) # index-based
itr = [Link]((x**2 for x in range(5)), dtype=int) # from generator
BASIC LEVEL QUESTIONS
Q1. Create: (a) 1-D array 0–9, (b) 4×4 identity, (c) 3×3 zeros float32, (d) 10 linearly spaced points from 0 to 100.
Q2. What is the difference between [Link]() and [Link]()? When would you choose empty?
Q1. Create a 5×5 checkerboard (0/1) array without using any explicit loops. Hint: use slicing.
Q2. Use [Link] to build an n×n multiplication table.
Q1. Create a structured array with fields 'name' (unicode, 10 chars), 'age' (int32), 'score' (float32) and populate it with 3
records. Demonstrate field-based access.
Q2. Explain the difference between [Link].default_rng(seed) and the legacy [Link](). Why is the new
Generator API preferred for reproducibility?
Page 7
NumPy & Pandas — Advanced Study Guide
Concept & Logic: Vectorization means expressing batch operations as array-level expressions rather than explicit
Python loops. NumPy delegates the loop to optimised C/Fortran code (BLAS/LAPACK). Embedding refers to how
multi-dimensional arrays are stored in a flat 1-D buffer and how strides map multi-D indices to that buffer.
import numpy as np
import time
# Loop (slow)
t0 = time.perf_counter()
result = [x**2 for x in arr]
print(f'Loop: {time.perf_counter()-t0:.4f}s')
# Vectorised (fast)
t0 = time.perf_counter()
result = arr ** 2
print(f'NumPy: {time.perf_counter()-t0:.4f}s') # ~50-200x faster
Q1. Replace the loop result = []; for x in arr: [Link](x*3+1) with a vectorised NumPy one-liner.
Q2. What does [Link]() return? How does it differ from [Link]()?
Q1. Given two (10000,) arrays x and y, compute the cosine distance (1 - dot(x,y)/(||x|| * ||y||)) without any Python loops.
Q2. Vectorise a sigmoid function σ(x) = 1 / (1 + e^-x) for a (1000, 1000) matrix.
Q1. Implement a vectorised batch matrix multiplication of two (B, M, K) and (B, K, N) arrays without [Link]. Use
[Link] and explain the notation.
Q2. Why does [Link]() sometimes return a view and sometimes a copy? Under what stride conditions can ravel return
a view?
Page 8
NumPy & Pandas — Advanced Study Guide
Concept & Logic: Every NumPy array has exactly one dtype. Knowing dtypes prevents silent overflow bugs (e.g.,
int8 max is 127). Type casting (astype) creates a new array; in-place casting is not possible without reassignment.
uint8 0 … 255
import numpy as np
Q1. Create an array [1,2,3,4] and cast it to float32, then to bool. What values do you get?
Q2. What happens when you add a float64 array to an int32 array? What is the result dtype?
Page 9
NumPy & Pandas — Advanced Study Guide
Q1. You have a uint8 image array (values 0–255). Normalise it to float32 in [0,1] using astype and arithmetic.
Q2. Explain safe vs unsafe casting in astype(). When does astype raise an error?
Q1. Design a function that automatically up-casts two arrays to a common safe dtype before performing arithmetic,
using np.result_type and np.can_cast.
Q2. What is a structured dtype? Create one for a student record and demonstrate vectorised field access.
Page 10
NumPy & Pandas — Advanced Study Guide
Concept & Logic: shape is a tuple (d0, d1, …, dn-1) describing the size along each axis. reshape() returns a view
when possible (contiguous memory) and a copy otherwise. The total number of elements ([Link](shape)) must
remain constant. Use -1 as a wildcard dimension to let NumPy infer it.
import numpy as np
a = [Link](24)
print([Link]) # (24,)
# ■■ reshape ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
b = [Link](4, 6) # 4 rows × 6 cols (view)
c = [Link](2, 3, 4) # 3-D (view)
d = [Link](6, -1) # -1 inferred as 4 → (6,4)
# using expand_dims
x = [Link]((3,4))
x3 = np.expand_dims(x, axis=0) # (1,3,4)
x3b = np.expand_dims(x, axis=2) # (3,4,1)
Q1. Reshape [Link](30) into (5,6), then into (2,3,5). Confirm total elements are the same.
Q2. What does [Link](-1) do? When does it return a view vs a copy?
Q1. You have a (100,) array of pixel brightness. Reshape it to (10,10), then add a channel axis to make it (10,10,1) as
required by a CNN.
Q2. Explain the difference between C-order and Fortran-order in reshape. Demonstrate with a (2,3) array.
Q1. Without using reshape, use [Link].stride_tricks.as_strided to re-interpret a (12,) int32 array as a (3,4) view. What are
the required strides?
Q2. Why can reshape return a copy when the array is non-contiguous (e.g. after transposing)? How can you force a
contiguous copy first?
Page 11
NumPy & Pandas — Advanced Study Guide
Concept & Logic: NumPy arithmetic is element-wise by default. Operations follow broadcasting rules when
shapes differ. [Link] is the vectorised ternary operator. [Link] handles multi-condition logic without loops.
import numpy as np
# ■■ [Link] ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
scores = [Link]([30, 110, 85, -5, 100])
print([Link](scores, 0, 100)) # [30 100 85 0 100]
BASIC LEVEL QUESTIONS
Q1. Given arr = [Link]([4,9,16,25]), compute its square root and integer floor using NumPy.
Q2. Write one line using [Link] to replace all values > 50 with 50 in a random 10-element array.
Q1. Implement ReLU (max(0, x)) and Leaky ReLU (x if x>0 else 0.01*x) using [Link] on a (-5,5) linspace of 100
points.
Q2. Normalise an array to zero mean and unit variance (z-score normalisation) in a single NumPy expression.
Page 12
NumPy & Pandas — Advanced Study Guide
Q1. Implement a piecewise function: f(x)= x^2 if x<0, sqrt(x) if 0<=x<=1, 1 otherwise — for a 1000-element array using
[Link] or [Link].
Q2. Explain why a *= 2 is faster than a = a * 2 for a large array. Under what conditions can in-place fail?
Page 13
NumPy & Pandas — Advanced Study Guide
Concept & Logic: A ufunc is a vectorised wrapper around a C-level function that operates element-wise on
arrays. They support broadcasting, type promotion, and optional output buffers. All standard math ops (+, *, sin,
exp, …) are ufuncs. You can create custom ufuncs with [Link] or numba @vectorize.
import numpy as np
x = [Link](-[Link], [Link], 6)
# ■■ Trigonometric ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print([Link](x))
print([Link](x))
print([Link](x))
# ■■ Rounding ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
a = [Link]([1.2, 1.5, 1.7, 2.5])
print([Link](a)) # [1. 1. 1. 2.]
print([Link](a)) # [2. 2. 2. 3.]
print([Link](a)) # [1. 2. 2. 2.] banker's rounding
relu_ufunc = [Link](my_relu, 1, 1)
print(relu_ufunc([Link]([-2, -1, 0, 1, 2])))
BASIC LEVEL QUESTIONS
Q1. Compute sin(x) and cos(x) for 100 evenly spaced values between 0 and 2π.
Q2. What is the difference between [Link]() and Python's built-in abs() when applied to an array?
Q1. Create a ufunc for the Gaussian function f(x) = exp(-x^2/2) / sqrt(2π) using [Link]. Compare its speed to a
vectorised NumPy expression.
Page 14
NumPy & Pandas — Advanced Study Guide
Q2. Explain how [Link]() differs from [Link](). Use [Link] to implement a scatter-add (histogram binning)
without [Link].
Page 15
NumPy & Pandas — Advanced Study Guide
Concept & Logic: NumPy supports four indexing modes: basic integer, basic slice (returns view), fancy (integer
array — returns copy), and boolean (returns copy). Slices follow Python's [start:stop:step] syntax; negative indices
wrap around.
import numpy as np
a = [Link](10) # [0 1 2 3 4 5 6 7 8 9]
# ■■ Slicing ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print(a[2:7]) # [2 3 4 5 6]
print(a[::2]) # [0 2 4 6 8] every 2nd
print(a[::-1]) # [9 8 7 6 5 4 3 2 1 0] reversed
print(a[1:8:3]) # [1 4 7]
Q1. Given a = [Link](20), extract: (a) elements 5–10 inclusive, (b) every 3rd element, (c) last 4 elements.
Q2. How do you extract the 2nd column from a (4,5) 2-D array?
Q1. Using fancy indexing, extract elements at positions [1,4,7,9] from a 1-D array and double them, then put them back
into the original array.
Q2. Explain why a_slice = a[2:5] shares memory with a but a_fancy = a[[2,3,4]] does not.
Q1. Implement a function extract_diagonal(m) that returns the diagonal of any 2-D array using only fancy indexing (no
[Link]).
Page 16
NumPy & Pandas — Advanced Study Guide
Q2. Using advanced indexing, assign 0 to all elements in a (5,5) array that are on even rows and odd columns —
without any loops.
Page 17
NumPy & Pandas — Advanced Study Guide
Concept & Logic: For N-D arrays, supply N comma-separated slice/index expressions. Ellipsis (...) expands to as
many ':' as needed to fill remaining axes. [Link] (alias for None) inserts a new size-1 dimension.
import numpy as np
# ■■ Ellipsis ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# For 5-D array shape (a,b,c,d,e)
data = [Link]((2, 3, 4, 5, 6))
print(data[0, ..., 0].shape) # (3,4,5) ellipsis fills axes 1-3
print(data[..., 2].shape) # (2,3,4,5) last axis indexed
Q1. Create a (4,4,4) array and extract: (a) the first 2×2×2 corner, (b) all elements along axis 1 at index 2.
Q2. What does t[..., 0] mean for a 4-D array? Write an equivalent explicit slice.
Q1. Given an image batch of shape (32, 224, 224, 3) (batch, H, W, C), extract the red channel for all images in one
slice.
Q2. Use [Link] to compute the Euclidean distance matrix between n points in d dimensions without loops.
Q1. Implement a function rolling_window(a, window) using multidimensional slicing and strides that returns a (n-w+1, w)
view of a 1-D array.
Q2. Describe how the ellipsis interacts with numpy's advanced (fancy) indexing. Does t[..., [0,2]] return a view or copy?
Justify.
Page 18
NumPy & Pandas — Advanced Study Guide
Concept & Logic: Splitting divides an array into sub-arrays. Broadcasting enables operations between arrays of
different (but compatible) shapes by virtually expanding dimensions. Concatenation joins arrays along an existing
axis; stacking adds a new axis.
import numpy as np
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SPLITTING
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
a = [Link](12)
parts = [Link](a, 3) # [0-3], [4-7], [8-11]
print(parts)
# 2-D split
m = [Link](16).reshape(4,4)
rows = [Link](m, 2) # split into top/bottom halves
cols = [Link](m, 2) # split into left/right halves
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# BROADCASTING
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
A = [Link]((3, 4))
v = [Link]([10, 20, 30, 40]) # shape (4,)
print(A + v) # v broadcasts over rows → (3,4)
# Column broadcast
col = [Link]([[1],[2],[3]]) # shape (3,1)
print(A + col) # col broadcasts over cols → (3,4)
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# CONCATENATION & STACKING
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
x = [Link]([[1,2],[3,4]])
y = [Link]([[5,6],[7,8]])
Page 19
NumPy & Pandas — Advanced Study Guide
Q1. Split [Link](18) into 3 equal parts. Then split it into parts of size 5, 7, 6.
Q2. What is the output shape of [Link]([[1],[2],[3]]) + [Link]([10,20,30,40])? Explain why.
Q1. Stack 5 grayscale images each of shape (64,64) to create a (5,64,64) batch tensor. Then add a channel dimension
to get (5,64,64,1).
Q2. Subtract the row-wise mean from a (100,20) matrix using broadcasting in one line.
Page 20
NumPy & Pandas — Advanced Study Guide
1.13 Aggregation
Concept & Logic: Aggregation functions reduce an array along one or more axes. Specifying axis=None
collapses all dimensions to a scalar. keepdims=True preserves the rank, enabling broadcasting of the result.
import numpy as np
m = [Link]([[4, 7, 2],
[1, 8, 3],
[9, 5, 6]])
# ■■ keepdims ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
row_mean = [Link](m, axis=1, keepdims=True) # shape (3,1)
centered = m - row_mean # broadcasts back to (3,3)
# ■■ Cumulative ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print([Link](m, axis=1)) # running row sums
print([Link]([Link]([1,2,3,4]))) # [1 2 6 24]
# ■■ Arg-reductions ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print([Link](m)) # 3 (flat index of minimum)
print([Link](m, axis=0)) # [2 1 2] row index of max per column
print([Link](m, axis=1)) # sort indices per row
Q1. Given a (5,4) array, compute the sum of each column and the max of each row.
Q2. What does keepdims=True do? Show how the result shape differs from keepdims=False.
Q1. Standardise (z-score) each column of a (1000,20) matrix using only [Link], [Link], and broadcasting.
Q2. Find the row index and column index of the global maximum in a 2-D array without np.unravel_index, then use it.
Q1. Implement a weighted mean function using [Link] and verify it with a manually computed value.
Q2. Compute the running 5-point moving average of a 100-element signal using [Link], then implement it with
[Link] for O(n) complexity.
Page 21
NumPy & Pandas — Advanced Study Guide
Concept & Logic: Boolean indexing uses a bool array of the same shape as a selector. It always returns a copy.
Combine masks with & (AND), | (OR), ~ (NOT) — NOT Python 'and/or/not' which do not work element-wise. [Link]
provides masked arrays that propagate NaN-like behaviour.
import numpy as np
Q1. Create a 10-element random integer array (0–100) and extract all values above 50 using boolean indexing.
Q2. Set all values equal to 0 in a (4,4) array to -1 using boolean masking.
Q1. Given a student scores array, mask all failing scores (<40) and compute the mean of passing scores only.
Q2. Use [Link] to mask outliers (values more than 3 standard deviations from mean) and compute the cleaned mean.
Q1. Implement a function multi_mask(arr, conditions) that accepts a list of (condition_array, replacement_value) tuples
and applies them sequentially.
Q2. Explain how boolean indexing with a 2-D mask on a 2-D array works. Does it return a 2-D result? Why?
Page 22
NumPy & Pandas — Advanced Study Guide
Concept & Logic: arr.T or [Link](arr) reverses the axis order (for N-D). For 2-D this is the classic matrix
transpose. T always returns a view — it only changes strides, not data. For general axis permutation use
[Link](arr, axes=(…)).
import numpy as np
# T is a view
A.T[0, 0] = 99
print(A[0, 0]) # 99 — same memory
# ■■ [Link] ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
img = [Link]((100, 200, 3)) # HWC format
chw = [Link](img, 0, 2) # → (3,200,100) roughly CHW
BASIC LEVEL QUESTIONS
Q1. Transpose a (4,6) matrix. What is the new shape? Verify with .shape.
Q2. Does m.T create a new array in memory? Prove it using np.shares_memory().
Q1. Convert an image batch from NHWC (N,H,W,C) to NCHW (N,C,H,W) format using [Link]. Provide the axes
argument.
Q2. Use the transpose to compute the dot product of each pair of rows in a (5,10) matrix (i.e., compute the Gram
matrix).
Q1. Explain why transposing a C-contiguous array produces a Fortran-contiguous result. How does this interact with
BLAS calls in [Link]?
Q2. You have a tensor of shape (B,T,H,D) (batch, time, heads, depth). Rearrange it to (B,H,T,D) using a single
[Link] call. Show the axes argument.
Page 23
NumPy & Pandas — Advanced Study Guide
Concept & Logic: A view shares memory with the original — changes propagate both ways. A copy is
independent. Views are created by basic slicing and T; copies are created by fancy indexing, boolean indexing,
[Link](), and .flatten(). Use np.shares_memory() or [Link] is not None to test.
import numpy as np
original = [Link](12).reshape(3, 4)
Q1. Create an array a, slice it as b = a[1:4], modify b, and show a has changed. Confirm with np.shares_memory.
Q2. What is [Link]? What does it return for an original array vs a view?
Q1. Write a function safe_modify(arr, idx, val) that modifies a copy of arr at index idx, leaving the original unchanged.
Q2. When would accidentally modifying a view cause a hard-to-find bug in a data pipeline? Give a realistic example.
Q1. Explain the WRITEABLE flag. How can you use [Link] = False to protect a shared array from accidental
modification?
Page 24
NumPy & Pandas — Advanced Study Guide
Q2. Does np.broadcast_to() return a view? Try to write to it and explain the error. How is this implemented using
strides?
Page 25
NumPy & Pandas — Advanced Study Guide
Concept & Logic: NumPy's float arrays use [Link] (IEEE 754 NaN) as a sentinel for missing values. Integer
arrays cannot store NaN — use float conversion or [Link] (masked arrays). NaN propagates through arithmetic;
use nan-safe functions ([Link], [Link], …) to ignore them.
import numpy as np
Q1. Create an array with three NaN values. Use [Link] to count them and [Link] to compute the mean.
Q2. What does np.nan_to_num() do? Replace NaN with 0 and inf with 999 in an example array.
Q1. Write a function impute_mean(arr) that replaces NaN in each column of a 2-D array with that column's mean.
Q2. An integer array cannot hold NaN. How would you represent missing integers? Demonstrate with a masked array.
Q1. Implement forward-fill (propagate last valid value forward) for a 1-D float array with NaNs using only NumPy (no
Pandas).
Page 26
NumPy & Pandas — Advanced Study Guide
Q2. Explain why [Link] != [Link] evaluates to True. How does this affect hashing and set membership, and how does
[Link]() work correctly?
Page 27
NumPy & Pandas — Advanced Study Guide
PART 2 — Pandas
Concept & Logic: NumPy is great for homogeneous numerical arrays, but real-world data is heterogeneous (ints,
strings, dates, booleans) and needs labels (column names, row indices). Pandas provides DataFrame (labeled 2-D
table) and Series (labeled 1-D array) built on NumPy, adding: missing value handling, SQL-like operations, time
series, and file I/O.
import pandas as pd
import numpy as np
Page 28
NumPy & Pandas — Advanced Study Guide
Concept & Logic: A Series is a 1-D labeled array. The index can be integers, strings, or dates. Values are
homogeneous (one dtype). Series is the building block of DataFrames (each column is a Series sharing the
DataFrame index).
import pandas as pd
import numpy as np
# ■■ Creation ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
s1 = [Link]([10, 20, 30, 40]) # default int index 0-3
s2 = [Link]([10,20,30], index=['a','b','c']) # custom index
s3 = [Link]({'x':1, 'y':2, 'z':3}) # from dict (keys=index)
s4 = [Link](5, index=range(4)) # scalar broadcast
# ■■ Indexing ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print(s2['b']) # 20 — label access
print(s2[1]) # 20 — integer positional (deprecated for ambiguous cases)
print([Link][1]) # 20 — always positional (safe)
print([Link]['b']) # 20 — always label (safe)
# ■■ Slicing ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print(s2['a':'b']) # inclusive of both ends with label slicing
print([Link][0:2]) # positional: rows 0 and 1
# ■■ Modification ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
s2['a'] = 100
[Link][2] = 999
# ■■ Sorting ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
unsorted = [Link]([30,10,20], index=['c','a','b'])
print(unsorted.sort_values()) # sorted by value
print(unsorted.sort_index()) # sorted by label
print(unsorted.sort_values(ascending=False)) # descending
Q1. Create a Series of 5 city names with a custom integer index starting at 1. Access the 3rd element using both label
and position.
Q2. Sort a Series of random floats first by value (descending), then by index (ascending).
Q1. Add two Series with partially overlapping indices. Handle the resulting NaN values using .fillna(0).
Q2. Given a Series with string index labels, use boolean masking to extract all values greater than the median.
Page 29
NumPy & Pandas — Advanced Study Guide
Q1. Create a Series with a DatetimeIndex (daily frequency for 2024). Resample to monthly averages and explain what
resampling does under the hood.
Q2. Explain the difference between .values (returns NumPy array), .array (returns ExtensionArray), and .to_numpy().
When does each matter?
Page 30
NumPy & Pandas — Advanced Study Guide
Concept & Logic: Boolean indexing in Pandas works like NumPy but respects the label-based index. Use &
(AND), | (OR), ~ (NOT) with parentheses around each condition. .query() provides a SQL-like string syntax. .isin(),
.between(), and .[Link]() are vectorised convenience methods.
import pandas as pd
import numpy as np
df = [Link]({
'name': ['Alice','Bob','Carol','Dave','Eve'],
'age': [25, 30, 22, 35, 28],
'score': [88, 72, 91, 65, 79],
'dept': ['IT','HR','IT','Finance','HR']
})
# ■■ .query() ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print([Link]('age > 25 and score > 75'))
threshold = 80
print([Link]('score > @threshold')) # @ for external var
# ■■ .isin() ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print(df[df['dept'].isin(['IT', 'Finance'])])
# ■■ .between() ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print(df[df['age'].between(25, 30)])
Q1. Filter a DataFrame to rows where salary > 50000 and department == 'Engineering'.
Q2. Use .isin() to select rows where a 'category' column contains 'A', 'B', or 'C'.
Q1. Using .query(), filter a large DataFrame for rows where price is between 10 and 50 and quantity > 100. Compare
speed with boolean indexing.
Q2. Select all rows where a 'description' column contains a regex pattern (e.g., any two consecutive digits) using
.[Link](regex=True).
Q1. Write a function dynamic_filter(df, **kwargs) that accepts column-value pairs and applies all conditions using
Boolean indexing, supporting both equality and range conditions.
Page 31
NumPy & Pandas — Advanced Study Guide
Q2. How does Pandas evaluate df[df['a'] > 5] internally? Trace through the __getitem__ and boolean Series operations.
Page 32
NumPy & Pandas — Advanced Study Guide
Concept & Logic: A DataFrame is a 2-D labeled table with potentially different dtypes per column. Internally it is a
dict of Series sharing one common Index. Columns are accessible as attributes ([Link]) or keys (df['col']); the latter
is always safe. Use [Link]() and [Link]() for quick EDA.
import pandas as pd
import numpy as np
# ■■ Inspection ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
print([Link]) # (4, 4)
print([Link]) # per-column dtype
print([Link]) # Index(['id','name','score','passed'])
print([Link]) # RangeIndex(start=0, stop=4, step=1)
[Link]() # memory, dtypes, non-null counts
print([Link]()) # stats for numeric columns
Q1. Create a DataFrame with columns 'product', 'price', 'stock'. Add a new column 'total_value' = price * stock.
Q2. What is the difference between df['col'] and [Link]? When can the latter fail?
Q1. Merge two DataFrames sharing a 'user_id' column using [Link](). Use all four join types: inner, left, right, outer.
Show the shape of each result.
Q2. Use pd.pivot_table to summarise total sales by month and category from a transactions DataFrame.
Page 33
NumPy & Pandas — Advanced Study Guide
Q1. Explain the MultiIndex. Create a DataFrame with a (Year, Month) MultiIndex and demonstrate .loc, .xs, and
.unstack on it.
Q2. How does Pandas copy-on-write (CoW) introduced in Pandas 2.0 change the behaviour of chained assignment?
Give a before/after example.
Page 34
NumPy & Pandas — Advanced Study Guide
Concept & Logic: .loc is label-based: rows and columns are selected by their actual index/column names. Label
slices are INCLUSIVE of both endpoints. .iloc is integer position-based (like NumPy indexing): EXCLUSIVE of
stop. Both accept scalar, list, slice, or boolean array selectors.
import pandas as pd
df = [Link]({
'name': ['Alice','Bob','Carol','Dave'],
'age': [25, 30, 22, 35],
'score': [88, 72, 91, 65]
}, index=['r0','r1','r2','r3'])
Q1. Use .loc to select rows where age > 25 and only return 'name' and 'score' columns.
Q2. Use .iloc to select the last 3 rows and the first 2 columns of any DataFrame.
Q1. Assign a value of 100 to the 'score' column for all rows where 'grade' == 'A' using .loc. Why is .loc preferred over
chained indexing here?
Q2. Demonstrate a SettingWithCopyWarning scenario (with chained indexing) and fix it with .loc.
Q1. Explain how .loc with a boolean array works when the index is not the default RangeIndex — specifically the
index-alignment behaviour.
Q2. Use .iloc inside a custom function that accepts row batches (for chunked processing) and applies a transformation.
Page 35
NumPy & Pandas — Advanced Study Guide
Concept & Logic: Pandas broadcasts scalar and Series operations across a DataFrame column-wise (axis=0 by
default) or row-wise (axis=1). .apply() runs a function along an axis; .applymap()/.map() on Series run
element-wise. Lambda functions provide concise inline transformations.
import pandas as pd
import numpy as np
df = [Link]({
'math': [80, 65, 90, 72],
'science': [75, 88, 70, 85],
'english': [90, 60, 85, 78]
})
Q1. Add a 'bonus' column equal to 5% of each row's 'salary' column using a lambda in .assign().
Q2. Use .apply() with a lambda to convert a 'temperature_C' column to Fahrenheit (F = C * 9/5 + 32).
Q1. Row-wise broadcast: normalise each row of a numeric DataFrame to sum to 1 using .apply(axis=1).
Page 36
NumPy & Pandas — Advanced Study Guide
Q2. Use .map() to replace string categories ('cat'/'dog'/'bird') with integer codes (0/1/2) in a Series.
Q1. Compare the performance of .apply(lambda), .map(), and a vectorised NumPy expression for transforming a
1M-row column. Profile all three.
Q2. Implement a custom aggregation function using .agg() that returns multiple statistics (mean, std, skewness) in a
single .groupby().agg() call.
Page 37
NumPy & Pandas — Advanced Study Guide
Concept & Logic: .rename() changes column or index labels without modifying data. .drop() removes rows
(axis=0) or columns (axis=1). Both return new DataFrames by default (inplace=True modifies in place). Use
errors='ignore' to silently skip non-existent labels.
import pandas as pd
# ■■ errors='ignore' ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
[Link](columns=['nonexistent'], errors='ignore') # no KeyError
# ■■ set_axis ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
df.set_axis(['col1','col2'], axis='columns', inplace=True)
BASIC LEVEL QUESTIONS
Q1. Rename columns 'fname' → 'first_name' and 'lname' → 'last_name'. Remove the 'temp' column.
Q2. Drop all rows with index 0, 3, or 5 from a DataFrame using .drop().
Q1. Write a clean_columns(df) function that strips whitespace, lowercases, and replaces spaces with underscores in all
column names using .rename().
Q2. Drop all columns that contain more than 40% missing values from a DataFrame.
Q1. Explain the Copy-on-Write implications of inplace=True in Pandas 2.x. Why is the Pandas team recommending
against inplace?
Q2. Use [Link]() and [Link]() to identify columns present in one DataFrame but not another,
then perform targeted drops.
Page 38
NumPy & Pandas — Advanced Study Guide
Concept & Logic: pd.read_csv / read_excel / read_json are the primary file I/O functions. Data cleaning involves:
handling missing values, fixing dtypes, removing unwanted characters, normalising strings, and validating ranges.
import pandas as pd
import numpy as np
Q1. Read a CSV with pd.read_csv(). Print shape, dtypes, and number of missing values per column.
Q2. Fill NaN in a numeric column with its median and NaN in a string column with 'Unknown'.
Page 39
NumPy & Pandas — Advanced Study Guide
Q1. Write a pipeline that: reads a CSV, strips whitespace from all string columns, converts a 'price' column with '$' signs
to float, and saves to a new CSV.
Q2. Use pd.read_csv with chunksize=1000 to process a large file in chunks and count total non-null rows.
Q1. Build a generic data_quality_report(df) function that returns: % missing per column, dtype per column, number of
duplicates, and outlier counts (IQR method) in a formatted DataFrame.
Q2. Explain the difference between [Link], [Link], None, and [Link]. When does each appear and how do they
interact with arithmetic?
Page 40
NumPy & Pandas — Advanced Study Guide
Concept & Logic: .duplicated() returns a boolean Series marking duplicate rows. .drop_duplicates() removes
them. Use subset= to consider only specific columns; keep= controls which occurrence to retain ('first','last',False).
import pandas as pd
df = [Link]({
'id': [1, 2, 2, 3, 4, 4, 4],
'name': ['A','B','B','C','D','D','D'],
'val': [10,20,20,30,40,40,99]
})
Q1. Create a DataFrame with 3 duplicate rows and show: total count, which rows are duplicates, and the cleaned
DataFrame.
Q2. How does keep='last' differ from keep='first' in drop_duplicates()?
Q1. For each duplicate group (same 'email'), keep only the most recent row based on a 'timestamp' column.
Q2. Identify columns that have only one unique value across the entire DataFrame (constant columns) and drop them.
Q1. Implement a fuzzy deduplication: use difflib to find rows where 'name' is >80% similar and flag them for manual
review.
Q2. Explain how drop_duplicates() handles NaN values. Do two NaN values in the same column count as duplicates?
Page 41
NumPy & Pandas — Advanced Study Guide
Concept & Logic: pd.to_datetime() converts strings/ints to Timestamp objects. DatetimeIndex unlocks .dt
accessor for year/month/day extraction, and resampling. pd.date_range() generates regular frequency ranges.
strftime/strptime format codes control string conversion.
import pandas as pd
import numpy as np
# ■■ pd.date_range ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
idx = pd.date_range('2024-01-01', periods=12, freq='MS') # month start
ts = [Link]([Link](12), index=idx)
# ■■ Resampling ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
daily_ts = [Link]([Link](365),
index=pd.date_range('2024-01-01', periods=365))
monthly = daily_ts.resample('ME').mean() # monthly average
weekly = daily_ts.resample('W').sum() # weekly sum
Q1. Parse a column of date strings in 'DD-MM-YYYY' format using pd.to_datetime with the format argument.
Q2. Extract year, month, and day of week from a datetime column using .dt accessor.
Q1. Compute the number of business days between two date columns using np.busday_count.
Page 42
NumPy & Pandas — Advanced Study Guide
Q2. Resample a daily time series of stock prices to weekly frequency, keeping the last price of each week.
Q1. Build a function that flags rows where a transaction date falls on a weekend or national holiday (using a custom
calendar).
Q2. Explain the difference between 'ME', 'MS', 'M' frequency aliases in pd.date_range. How did these change from
Pandas 2.2?
Page 43
NumPy & Pandas — Advanced Study Guide
Concept & Logic: GroupBy implements the split-apply-combine pattern. .transform() returns a result with the
same shape as the input (useful for broadcasting group statistics back to original rows). .agg() applies multiple
functions; .apply() handles complex custom logic per group.
import pandas as pd
import numpy as np
df = [Link]({
'dept': ['IT','IT','HR','HR','IT','HR'],
'name': ['Alice','Bob','Carol','Dave','Eve','Frank'],
'salary': [80000,75000,60000,65000,90000,55000],
'years': [3,5,2,7,1,4]
})
print([Link]('dept').apply(top2, include_groups=False))
Q1. Group a sales DataFrame by 'region' and compute the total and average revenue per region.
Q2. What does .transform('mean') return compared to .agg('mean')? Show the shape difference.
Q1. Compute a within-group z-score for each employee's salary using .groupby() + .transform().
Q2. Use .filter() to remove all groups where any member's salary is below 40000.
Q1. Implement a rolling 3-month revenue moving average per product using .groupby() + .rolling() + .mean(). Handle
the warm-up period correctly.
Page 44
NumPy & Pandas — Advanced Study Guide
Q2. Explain the performance implications of .apply() vs .transform() for large DataFrames. When should you vectorise
instead?
Page 45