NumPy Crash Course

NumPy is the bedrock of Python data science — every major ML library (Pandas, Scikit-learn, PyTorch) is built on top of NumPy arrays.

1. What You'll Learn


2. A Real Story from a Data Engineer

(1) The Pain: Python Lists Are Too Slow for Millions of Rows

Bob needed to compute monthly sales statistics across 12 months and 5 product categories — 60 thousand records. Using native Python list loops to calculate the mean and standard deviation took over 30 seconds, and Alice's US dataset with 500 thousand records simply froze. Native Python loops are the bottleneck of ML data processing.

(2) NumPy's Solution

NumPy's ndarray uses contiguous memory blocks and C-level low-level operations, making vectorized computations 50–100x faster than Python loops.

PYTHON
import numpy as np

# Python list loop vs NumPy vectorization
sales_list = list(range(1, 60001))     # 60,000 records
sales_arr = np.array(sales_list)

# NumPy vectorized: 100x faster
mean_val = sales_arr.mean()
std_val = sales_arr.std()
print(f"Mean: {mean_val:.2f}, Std: {std_val:.2f}")

(3) The Payoff: Computation Time Drops from 30s to 0.3s

After Bob migrated his data processing from Python loops to NumPy vectorization, statistical computations on 60 thousand records dropped from 30 seconds to 0.3 seconds. Alice's 500 thousand records also complete in under 1 second.


3. ndarray Creation and Shape Manipulation

The ndarray is NumPy's core data structure — a multi-dimensional array of same-type elements stored in contiguous memory.

(1) Creating Arrays

PYTHON
import numpy as np

# From Python list
a = np.array([1, 2, 3, 4, 5])

# Built-in constructors
zeros = np.zeros((3, 4))        # 3x4 matrix of zeros
ones = np.ones((2, 3))          # 2x3 matrix of ones
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]

print(f"arange: {range_arr}")
print(f"linspace: {linspace}")

▶ Example: Creating the SalesPredict Sales Matrix

PYTHON
import numpy as np

# Monthly sales for 5 categories over 12 months (in thousand USD)
sales = np.array([
    [120, 135, 150, 142, 160, 175, 180, 190, 195, 200, 220, 250],  # Electronics
    [80, 85, 90, 88, 95, 100, 105, 108, 110, 115, 130, 145],       # Clothing
    [50, 48, 55, 60, 58, 62, 65, 68, 70, 72, 80, 90],              # Food
    [30, 35, 40, 38, 42, 45, 48, 50, 52, 55, 60, 70],              # Books
    [200, 210, 225, 220, 240, 260, 270, 280, 290, 300, 350, 400],  # Home
])

print(f"Shape: {sales.shape}")
print(f"Total annual revenue: {sales.sum() / 1000:.1f} million USD")
print(f"Q4 revenue: {sales[:, 9:].sum() / 1000:.1f} million USD")

Output:

TEXT
Shape: (5, 12)
Total annual revenue: 6.3 million USD
Q4 revenue: 2.3 million USD

(2) Shape Operations

Operation Method Description
Reshape reshape() Changes the view without altering the data
Transpose T or transpose() Swaps rows and columns
Flatten flatten() / ravel() Multi-dimensional → 1D
Add dimension np.newaxis / expand_dims Adds a new axis

▶ Example: reshape and transpose

PYTHON
import numpy as np

# Reshape: 1D to 2D
data = np.arange(12)
matrix = data.reshape(3, 4)
print(f"Reshaped to 3x4:\n{matrix}")

# Transpose: swap rows and columns
transposed = matrix.T
print(f"Transposed to 4x3:\n{transposed}")

# -1 means auto-calculate dimension
auto_reshape = data.reshape(2, -1)
print(f"Auto reshape (2, -1): shape={auto_reshape.shape}")

Output:

TEXT
# Executed successfully

(3) The Broadcasting Mechanism

Broadcasting allows arrays of different shapes to automatically expand during arithmetic operations, eliminating the need to manually copy data.

100%
graph TB
    A[Scalar + Array] --> B["Scalar broadcast to array shape"]
    C["1D + 2D Array"] --> D["1D broadcast along axis 0"]
    E["Shape (3,1) + (1,4)"] --> F["Both broadcast to (3,4)"]

▶ Example: Broadcasting in Practice

PYTHON
import numpy as np

# Scalar + array: scalar broadcasts
prices = np.array([100, 200, 300, 400])
discount = 0.9  # 10% off
print(f"Discounted prices: {prices * discount}")

# 1D + 2D: row broadcasts across rows
monthly_sales = np.array([[100, 200], [110, 210], [120, 220]])  # 3 months x 2 categories
growth_rate = np.array([1.05, 1.10])  # different growth per category
print(f"Projected sales:\n{monthly_sales * growth_rate}")

# Column + row broadcast
col = np.array([[1], [2], [3]])   # shape (3, 1)
row = np.array([10, 20, 30, 40])  # shape (4,)
print(f"Col + Row result shape: {(col + row).shape}")

Output:

TEXT
# Executed successfully

4. Array Indexing and Slicing

(1) Basic Indexing and Slicing

PYTHON
import numpy as np

arr = np.arange(10)
print(f"arr[3]: {arr[3]}")          # Single element
print(f"arr[2:7]: {arr[2:7]}")      # Slice
print(f"arr[::2]: {arr[::2]}")      # Step=2

# 2D indexing
matrix = np.arange(12).reshape(3, 4)
print(f"matrix[1, 2]: {matrix[1, 2]}")       # Row 1, Col 2
print(f"matrix[0, :]: {matrix[0, :]}")       # Entire row 0
print(f"matrix[:, 1]: {matrix[:, 1]}")       # Entire col 1

(2) Boolean Indexing

▶ Example: Filtering High-Sales Categories

PYTHON
import numpy as np

# Category monthly sales (thousand USD)
sales = np.array([250, 145, 90, 70, 400])
categories = np.array(["Electronics", "Clothing", "Food", "Books", "Home"])

# Boolean indexing: find categories above 100k
high_sales = sales > 100
print(f"High sales mask: {high_sales}")
print(f"High sales categories: {categories[high_sales]}")
print(f"High sales values: {sales[high_sales]}")

# Compound conditions
mid_range = (sales >= 80) & (sales <= 200)
print(f"Mid-range categories: {categories[mid_range]}")

Output:

TEXT
# Executed successfully

(3) Fancy Indexing

▶ Example: Selecting Specific Months and Categories

PYTHON
import numpy as np

sales = np.arange(60).reshape(5, 12)  # 5 categories x 12 months

# Select specific months: Jan, Apr, Jul, Oct (indices 0,3,6,9)
quarterly = sales[:, [0, 3, 6, 9]]
print(f"Quarterly data shape: {quarterly.shape}")

# Select top 3 categories by total sales
total = sales.sum(axis=1)
top3_idx = np.argsort(total)[-3:]
print(f"Top 3 category indices: {top3_idx}")
print(f"Top 3 total sales: {total[top3_idx]}")

Output:

TEXT
# Executed successfully
Indexing Method Syntax Returned Dimensions Use Case
Basic indexing arr[2] Reduces dimension Access a single element
Slicing arr[1:5] Same dimension Access a contiguous range
Boolean indexing arr[mask] 1D Conditional filtering
Fancy indexing arr[[1,3,5]] Same dimension Access non-contiguous positions

5. Numerical Computing and Statistics

(1) Vectorized Operations

NumPy's vectorized operations replace Python loops and are the core of its performance advantage.

▶ Example: Vectorization vs. Loop Performance Comparison

PYTHON
import numpy as np
import time

size = 1_000_000
a = np.random.rand(size)
b = np.random.rand(size)

# Vectorized computation
start = time.time()
c = a + b
vec_time = time.time() - start

# Python loop (slow!)
start = time.time()
c_list = [a[i] + b[i] for i in range(size)]
loop_time = time.time() - start

print(f"Vectorized: {vec_time:.4f}s")
print(f"Loop: {loop_time:.4f}s")
print(f"Speedup: {loop_time / vec_time:.0f}x")

Output:

TEXT
# Executed successfully

(2) Statistical Functions

▶ Example: SalesPredict Sales Statistics

PYTHON
import numpy as np

# Daily sales data for 30 days (thousand USD)
daily_sales = np.array([
    45, 52, 48, 61, 55, 72, 68, 50, 53, 49,
    58, 63, 71, 66, 59, 54, 47, 70, 75, 62,
    51, 57, 64, 69, 73, 60, 56, 67, 74, 78
])

print(f"Mean: {daily_sales.mean():.1f}k USD")
print(f"Median: {np.median(daily_sales):.1f}k USD")
print(f"Std: {daily_sales.std():.1f}k USD")
print(f"Min: {daily_sales.min()}k USD")
print(f"Max: {daily_sales.max()}k USD")
print(f"Total: {daily_sales.sum()}k USD")

# Cumulative sum for trend
cum_sales = daily_sales.cumsum()
print(f"Day 30 cumulative: {cum_sales[-1]}k USD")

Output:

TEXT
# Executed successfully

(3) Matrix Operations

▶ Example: Ad Spend ROI Matrix Calculation

PYTHON
import numpy as np

# Ad spend per channel (3 channels) x 4 products
ad_matrix = np.array([
    [10, 15, 8, 12],   # Google Ads (thousand USD)
    [5, 20, 10, 8],    # Facebook Ads
    [3, 7, 15, 10],    # Email Marketing
])

# Conversion rate matrix (channel x product)
conv_rate = np.array([
    [0.05, 0.03, 0.08, 0.04],
    [0.03, 0.06, 0.04, 0.05],
    [0.10, 0.08, 0.12, 0.09],
])

# Revenue per conversion (per product, thousand USD)
revenue_per_conv = np.array([50, 30, 80, 40])

# Matrix multiply: expected conversions
expected_conv = ad_matrix * conv_rate  # element-wise
# Total revenue per product
total_revenue = expected_conv.sum(axis=0) * revenue_per_conv
print(f"Revenue by product: {total_revenue} thousand USD")
print(f"Total ROI revenue: {total_revenue.sum():.1f} thousand USD")

Output:

TEXT
# Executed successfully

6. Random Numbers and Linear Algebra

(1) Random Number Generation

PYTHON
import numpy as np

rng = np.random.default_rng(seed=42)  # Reproducible

# Common distributions
uniform = rng.uniform(0, 100, size=5)    # Uniform [0, 100)
normal = rng.normal(50, 10, size=5)      # Normal(mean=50, std=10)
integers = rng.integers(1, 100, size=5)  # Random integers [1, 100)
choice = rng.choice(["A", "B", "C"], size=5)  # Random choice

print(f"Uniform: {uniform}")
print(f"Normal: {normal}")
print(f"Integers: {integers}")

(2) Linear Algebra

▶ Example: Linear Regression Normal Equation

PYTHON
import numpy as np

# Simulate: sales = 50 + 0.8 * ad_spend + noise
rng = np.random.default_rng(42)
n = 100
ad_spend = rng.uniform(10, 100, n)
noise = rng.normal(0, 5, n)
sales = 50 + 0.8 * ad_spend + noise

# Solve with normal equation: w = (X^T X)^-1 X^T y
X = np.column_stack([np.ones(n), ad_spend])  # Add bias column
w = np.linalg.inv(X.T @ X) @ X.T @ y := sales
# Note: fixed syntax below
w = np.linalg.inv(X.T @ X) @ (X.T @ sales)

print(f"Intercept: {w[0]:.2f}")
print(f"Coefficient: {w[1]:.2f}")
print(f"True values: intercept=50, coeff=0.8")

Output:

TEXT
# Executed successfully
Function Purpose Syntax
np.dot / @ Matrix multiplication A @ B
np.linalg.inv Matrix inverse inv(A)
np.linalg.det Determinant det(A)
np.linalg.norm Vector/matrix norm norm(v)
np.linalg.svd Singular value decomposition U, S, Vt = svd(A)
np.linalg.solve Solve linear systems solve(A, b)

❓ FAQ

Q What is the fundamental difference between an ndarray and a Python list?
A An ndarray has uniform element types, contiguous memory, and supports vectorized operations; a list has mixed types, scattered memory, and can only be processed with loops. ndarrays are 50–100x faster for numerical computing.
Q Does reshape copy the data?
A No. reshape returns a view of the original data without copying memory. However, if the shapes are incompatible (e.g., non-contiguous memory), it will automatically make a copy. Use the .base attribute to check whether something is a view.
Q What are the rules of broadcasting?
A Dimensions are aligned from the rightmost axis. Any dimension that is 1 or missing is automatically expanded. Two dimensions must either be equal or one of them must be 1; otherwise, an error is raised.
Q When should I use np.random.seed vs. np.random.default_rng?
A Use default_rng (the newer API) — seed belongs to the legacy API. default_rng uses the PCG64 algorithm, which has better statistical quality and does not affect global state.
Q How do I tell if two arrays share memory?
A Use np.shares_memory(a, b) to check. Alternatively, check whether a.base is b or b.base is a. When memory is shared, modifying one array will affect the other.
Q Why is NumPy considered the foundation of ML?
A Pandas is built on NumPy arrays under the hood, Scikit-learn's inputs and outputs are all NumPy ndarrays, and PyTorch tensors are highly compatible with NumPy. Mastering NumPy means mastering the data language of ML.

📖 Summary


📝 Exercises

  1. Basic (Difficulty ⭐): Create a 5x5 matrix with values from 1 to 25, then use slicing to extract the diagonal elements. Hint: diagonal elements have the same row and column index, or use np.diag().
  2. Intermediate (Difficulty ⭐⭐): Generate 1000 random sales data points from a normal distribution N(100, 15), use boolean indexing to filter values above 130, and calculate their proportion. Hint: use rng.normal() and boolean indexing.
  3. Challenge (Difficulty ⭐⭐⭐): Implement multiple linear regression using NumPy's normal equation. Assume sales = 20 + 3ad_spend + 1.5traffic + noise. Generate simulated data, solve for the coefficients, and compare them with the true coefficients. Hint: add a bias column when building the X matrix, and use np.linalg.inv with matrix multiplication.

← Previous: Introduction to Machine Learning | Next: Data Processing with Pandas →

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏