🎯 Mục tiêu bài học
Sau bài thực hành này, bạn sẽ:
✅ Thành thạo tạo và thao tác ndarray trong mọi tình huống
✅ Sử dụng Boolean Indexing và Fancy Indexing tự tin
✅ Áp dụng Broadcasting trong tính toán thực tế
✅ Giải quyết bài toán thống kê và xử lý dữ liệu bằng NumPy
Thời gian: 2 giờ | Độ khó: Beginner → Hard | Yêu cầu: Hoàn thành Bài 4 (NumPy)
🟢 Phần 1: Tạo và Thao tác Array (Easy)
Ôn lại lý thuyết (Bài 4):
np.array()từ list,np.arange()giống range(),np.linspace()chia đềunp.zeros(),np.ones(),np.eye()tạo mảng đặc biệtreshape()thay đổi shape,-1tự tính chiều- Các thuộc tính:
shape,ndim,size,dtype
Bài 1.1: Khởi tạo cơ bản
1import numpy as np23# Bài tập: Tạo các mảng sau4a = np.arange(1, 21) # [1, 2, ..., 20]5b = np.linspace(0, 1, 11) # [0, 0.1, 0.2, ..., 1.0]6c = np.zeros((3, 5)) # Ma trận 3x5 toàn 07d = np.eye(4) # Ma trận đơn vị 4x489# Kiểm tra10print(f"a: shape={a.shape}, dtype={a.dtype}")11print(f"b: {b}")12print(f"c: shape={c.shape}")13print(f"d:\n{d}")Bài 1.2: Reshape Challenge
Đề bài: Tạo mảng 1-24, reshape thành các shape khác nhau
1arr = np.arange(1, 25)23# (a) Reshape thành 4x64a = arr.reshape(4, 6)5print(a)67# (b) Reshape thành 2x3x4 (3D)8b = arr.reshape(2, 3, 4)9print(b.shape) # (2, 3, 4)1011# (c) Reshape thành 6x4 rồi transpose thành 4x612c = arr.reshape(6, 4).T13print(c.shape) # (4, 6)1415# (d) -1 tự tính16d = arr.reshape(3, -1) # → (3, 8)17print(d.shape)Bài 1.3: Array Attributes
Đề bài: Tạo mảng random 5x5 và in tất cả thuộc tính
1np.random.seed(42)2arr = np.random.randint(1, 100, (5, 5))34print(f"Array:\n{arr}")5print(f"Shape: {arr.shape}")6print(f"Ndim: {arr.ndim}")7print(f"Size: {arr.size}")8print(f"Dtype: {arr.dtype}")9print(f"Bytes: {arr.nbytes}")10print(f"Min: {arr.min()} at index {arr.argmin()}")11print(f"Max: {arr.max()} at index {arr.argmax()}")Checkpoint
Bạn đã tạo thành công mảng 3D chưa? Hãy chắc chắn bạn hiểu shape (2, 3, 4) nghĩa là gì!
🟡 Phần 2: Indexing và Filtering (Medium)
Ôn lại lý thuyết (Bài 4):
- Indexing:
a[0],matrix[i, j],a[:, 0](cột 0) - Boolean Indexing:
a[a > 5]→ lọc theo điều kiện - Fancy Indexing:
a[[1,3,5]]→ chọn theo list index - np.where():
np.where(condition, x, y)→ chọn yếu tố - NaN handling:
np.isnan(),np.nanmean(),np.nanmedian()
Bài 2.1: Trích xuất dữ liệu
Đề bài: Cho bảng điểm, trích xuất theo nhiều cách
1np.random.seed(42)2# 10 sinh viên × 4 môn (Math, Physics, Chemistry, Biology)3scores = np.random.randint(40, 100, (10, 4))4subjects = ["Math", "Physics", "Chemistry", "Biology"]56# (a) Điểm Toán của sinh viên thứ 3 (index 2)7print(f"SV3 Math: {scores[2, 0]}")89# (b) Tất cả điểm Hóa học10print(f"Chemistry: {scores[:, 2]}")1112# (c) Sinh viên 1-5, 2 môn đầu13print(f"Top5, Math+Phys:\n{scores[:5, :2]}")1415# (d) Sinh viên có điểm Toán > 7016mask = scores[:, 0] > 7017print(f"Math > 70:\n{scores[mask]}")1819# (e) Số sinh viên đạt (≥ 50) tất cả các môn20all_pass = np.all(scores >= 50, axis=1)21print(f"Đạt tất cả: {np.sum(all_pass)}/{len(scores)} sinh viên")Bài 2.2: Thay thế và Cập nhật
Đề bài: Xử lý dữ liệu bất thường trong mảng
1data = np.array([23, 45, -999, 67, 89, -999, 12, -999, 56, 78])23# (a) Thay -999 bằng NaN4clean = data.astype(float)5clean[clean == -999] = np.nan6print(f"Clean: {clean}")78# (b) Đếm giá trị valid9valid_count = np.sum(~np.isnan(clean))10print(f"Valid: {valid_count}/{len(clean)}")1112# (c) Tính mean bỏ qua NaN13print(f"Mean: {np.nanmean(clean):.1f}")1415# (d) Thay NaN bằng median16median_val = np.nanmedian(clean)17clean[np.isnan(clean)] = median_val18print(f"Filled: {clean}")Bài 2.3: np.where — Conditional Selection
Đề bài: Phân loại sinh viên dựa trên điểm
1np.random.seed(42)2scores = np.random.randint(0, 100, 20)34# Phân loại: A (≥90), B (≥80), C (≥70), D (≥60), F (<60)5grades = np.where(scores >= 90, "A",6 np.where(scores >= 80, "B",7 np.where(scores >= 70, "C",8 np.where(scores >= 60, "D", "F"))))910for s, g in zip(scores[:10], grades[:10]):11 print(f" {s} → {g}")1213# Đếm mỗi loại14unique, counts = np.unique(grades, return_counts=True)15for grade, count in zip(unique, counts):16 print(f" {grade}: {count} sinh viên")Checkpoint
Boolean indexing là kỹ thuật QUAN TRỌNG NHẤT trong NumPy. Bạn đã filter được dữ liệu bằng mask chưa?
🟡 Phần 3: Broadcasting và Toán học (Medium)
Ôn lại lý thuyết (Bài 4):
- Broadcasting: Tự động mở rộng shape để tính toán → không cần vòng lặp!
- Quy tắc:
(3,) + (3,1)→ broadcast thành(3,3) - Thêm chiều:
arr[:, np.newaxis]hoặcarr[:, None] - Ứng dụng: Normalization, distance matrix, outer product
- Hàm toán:
np.mean(axis=0),np.sum(),np.dot(),np.sqrt()
Bài 3.1: Min-Max Normalization
Đề bài: Chuẩn hóa dữ liệu về khoảng [0, 1] bằng Broadcasting
1# Dữ liệu: 5 sinh viên × 3 features (Age, Income, Score)2data = np.array([[22, 30000, 85],3 [35, 75000, 92],4 [28, 45000, 78],5 [45, 95000, 88],6 [19, 20000, 95]])78# Min-Max: x_norm = (x - min) / (max - min)9data_min = data.min(axis=0) # [19, 20000, 78]10data_max = data.max(axis=0) # [45, 95000, 95]1112normalized = (data - data_min) / (data_max - data_min) # Broadcasting!13print(f"Normalized:\n{normalized.round(3)}")14# Tất cả giá trị nằm trong [0, 1]Bài 3.2: Distance Matrix
Đề bài: Tính khoảng cách Euclidean giữa các điểm 2D
1# 4 điểm 2D2points = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])34# Tính pairwise distance bằng broadcasting5# Reshape để broadcast: (4,1,2) - (1,4,2) = (4,4,2)6diff = points[:, np.newaxis, :] - points[np.newaxis, :, :]7distances = np.sqrt(np.sum(diff**2, axis=2))89print("Distance Matrix:")10print(distances.round(3))11# [[0. 1. 1. 1.414]12# [1. 0. 1.414 1. ]13# [1. 1.414 0. 1. ]14# [1.414 1. 1. 0. ]]Bài 3.3: Outer Product cho phân tích
Đề bài: Dùng outer product để tạo bảng phí giao hàng (khoảng cách × giá/km)
1distances = np.array([5, 10, 20, 50, 100]) # km2price_per_km = np.array([1.5, 2.0, 3.0, 5.0]) # $/km34# Outer product5fee_table = distances[:, np.newaxis] * price_per_km[np.newaxis, :]6# hoặc: fee_table = np.outer(distances, price_per_km)78print("Bảng phí giao hàng ($):")9print(f"{'km':<6}", end="")10for p in price_per_km:11 print(f" ${p}/km", end="")12print()13for i, d in enumerate(distances):14 print(f"{d:<6}", end="")15 for j in range(len(price_per_km)):16 print(f" ${fee_table[i,j]:>5.0f}", end="")17 print()Checkpoint
Bạn đã hiểu trick [:, np.newaxis] để thêm chiều cho broadcasting chưa? Đây là kỹ thuật nâng cao rất hữu ích!
🔴 Phần 4: Bài Toán Thực Tế (Hard)
Đây là phần nâng cao! Các bài này kết hợp nhiều kỹ thuật NumPy:
- Monte Carlo simulation:
np.random+ boolean indexing - Image processing: mảng 3D + slicing + broadcasting
- Time series: vectorization + cumsum trick
Nếu khó, hãy đọc solution rồi thử tự code lại!
Bài 4.1: Mô phỏng Monte Carlo — Ước tính π
Đề bài: Dùng random để ước lượng số Pi
1def estimate_pi(n_points=1_000_000):2 """3 Ý tưởng: Ném random điểm vào hình vuông [-1,1]x[-1,1].4 Tỉ lệ điểm rơi trong hình tròn ≈ π/45 """6 rng = np.random.default_rng(42)7 8 # Random x, y trong [-1, 1]9 x = rng.uniform(-1, 1, n_points)10 y = rng.uniform(-1, 1, n_points)11 12 # Kiểm tra trong hình tròn: x² + y² ≤ 113 inside = (x**2 + y**2) <= 114 15 pi_estimate = 4 * np.sum(inside) / n_points16 return pi_estimate1718for n in [1000, 10000, 100000, 1_000_000]:19 pi = estimate_pi(n)20 error = abs(pi - np.pi)21 print(f" n={n:>10,}: π ≈ {pi:.6f} (error: {error:.6f})")Bài 4.2: Image Processing cơ bản
Đề bài: Xử lý ảnh dùng NumPy (ảnh = mảng 3D)
1# Giả lập ảnh 100x100 RGB2np.random.seed(42)3image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)4print(f"Image shape: {image.shape}") # (100, 100, 3)56# (a) Grayscale: Y = 0.299R + 0.587G + 0.114B7weights = np.array([0.299, 0.587, 0.114])8gray = np.dot(image, weights).astype(np.uint8)9print(f"Grayscale shape: {gray.shape}") # (100, 100)1011# (b) Brightness: tăng sáng 50 (clip ở 255)12brighter = np.clip(image.astype(int) + 50, 0, 255).astype(np.uint8)1314# (c) Flip: lật ngang15flipped = image[:, ::-1, :]1617# (d) Crop: lấy vùng trung tâm 50x5018h, w = image.shape[:2]19crop = image[h//4:3*h//4, w//4:3*w//4, :]20print(f"Cropped shape: {crop.shape}") # (50, 50, 3)2122# (e) Histogram23for i, color in enumerate(["Red", "Green", "Blue"]):24 channel = image[:, :, i]25 print(f" {color}: mean={channel.mean():.1f}, std={channel.std():.1f}")Bài 4.3: Moving Average cho dữ liệu chuỗi thời gian
Đề bài: Tính moving average cho dữ liệu giá cổ phiếu
1def moving_average(data, window):2 """Tính simple moving average (SMA)"""3 # Cách 1: cumsum trick4 cumsum = np.cumsum(data)5 cumsum = np.insert(cumsum, 0, 0)6 return (cumsum[window:] - cumsum[:-window]) / window78# Giả lập giá cổ phiếu 100 ngày9np.random.seed(42)10price = 100 + np.cumsum(np.random.randn(100) * 2)1112# Tính SMA13sma_7 = moving_average(price, 7)14sma_20 = moving_average(price, 20)1516print(f"Price: {len(price)} days, last 5: {price[-5:].round(2)}")17print(f"SMA7: {len(sma_7)} values, last 5: {sma_7[-5:].round(2)}")18print(f"SMA20: {len(sma_20)} values, last 5: {sma_20[-5:].round(2)}")1920# Tín hiệu: SMA7 cắt SMA20 từ dưới lên → Buy signal21# (Advanced trick dùng boolean indexing)Monte Carlo simulation là kỹ thuật quan trọng trong finance, ML, và physics. Bạn sẽ gặp lại trong khóa ML!
Checkpoint
Bạn đã giải được ít nhất 1 bài Hard chưa? Bài Monte Carlo Pi là ví dụ kinh điển về sức mạnh NumPy!
📝 Tổng Kết
Câu hỏi tự kiểm tra
- Khi nào nên dùng
np.where()thay vì boolean indexing đơn giản? - Monte Carlo simulation là gì và tại sao NumPy phù hợp để thực hiện nó?
- Moving average (trung bình trượt) dùng để làm gì trong phân tích dữ liệu chuỗi thời gian?
- Làm thế nào để chuyển ảnh RGB sang grayscale bằng NumPy? Công thức nào được sử dụng?
✅ Checklist hoàn thành
- 🟢 Phần 1 (Easy): Tạo array, reshape — xong?
- 🟡 Phần 2 (Medium): Indexing, boolean mask, np.where — xong?
- 🟡 Phần 3 (Medium): Broadcasting, normalization, distance — xong?
- 🔴 Phần 4 (Hard): Monte Carlo, image processing, moving average — xong?
NumPy Cheat Sheet
1import numpy as np23# Create4np.array(), np.zeros(), np.ones(), np.arange(), np.linspace()56# Index7a[mask], np.where(cond, x, y), a[a > 0]89# Reshape10a.reshape(m, n), a.ravel(), a.T, np.vstack/hstack()1112# Math13np.mean(), np.std(), np.sum(), np.cumsum()14np.dot(), a @ b, np.linalg.inv()1516# Random17rng = np.random.default_rng(42)18rng.random(), rng.normal(), rng.integers()Bài tiếp theo: Pandas — Thư viện xử lý dữ liệu dạng bảng #1 cho Data Science! 📊
