MinAI - Về trang chủ
Lý thuyết
4/153 giờ
Đang tải...

NumPy — Nền Tảng Tính Toán Khoa Học

Thành thạo NumPy arrays, indexing, broadcasting, và các hàm toán học/thống kê

0

🎯 Mục tiêu bài học

TB5 min

Sau bài học này, bạn sẽ:

✅ Hiểu tại sao NumPy nhanh hơn Python list hàng trăm lần

✅ Tạo, thao tác và biến đổi ndarray thành thạo

✅ Áp dụng Broadcasting để tính toán hiệu quả

✅ Sử dụng các hàm toán học, thống kê, và random trong NumPy

✅ Chuẩn bị nền tảng cho Pandas, Matplotlib, Scikit-learn

Thời gian: 3 giờ | Độ khó: Beginner → Intermediate | Yêu cầu: Python cơ bản (Bài 1-3)

1

📖 Bảng Thuật Ngữ Quan Trọng

TB5 min
Thuật ngữTiếng ViệtMô tả
ndarrayMảng N chiềuCấu trúc dữ liệu cốt lõi của NumPy
VectorizationVéc-tơ hóaThao tác trên toàn bộ mảng thay vì từng phần tử
BroadcastingPhát sóngTự động mở rộng shape để thực hiện phép tính
ShapeKích thướcTuple mô tả số phần tử mỗi chiều
dtypeKiểu dữ liệuKiểu phần tử trong mảng (int32, float64...)
IndexingChỉ mụcTruy cập phần tử theo vị trí
SlicingCắt látTrích xuất một phần mảng
AxisTrụcChiều tính toán (0=dọc, 1=ngang)
ReshapeBiến đổi hình dạngThay đổi shape mà không đổi dữ liệu
Universal Function (ufunc)Hàm toàn cụcHàm áp dụng element-wise lên mảng

Checkpoint

Bạn có thể giải thích sự khác biệt giữa Vectorization và Broadcasting không? Đây là 2 khái niệm quan trọng nhất!

2

📚 Tại sao cần NumPy?

TB5 min

Vấn đề với Python List

Python list linh hoạt nhưng chậm khi xử lý dữ liệu lớn:

Python
1import time
2
3# Python list: cộng 1 triệu phần tử
4py_list = list(range(1_000_000))
5start = time.time()
6result = [x * 2 for x in py_list]
7py_time = time.time() - start
8
9# NumPy: cộng 1 triệu phần tử
10import numpy as np
11np_arr = np.arange(1_000_000)
12start = time.time()
13result = np_arr * 2
14np_time = time.time() - start
15
16print(f"Python list: {py_time:.4f}s")
17print(f"NumPy array: {np_time:.4f}s")
18print(f"NumPy nhanh hơn: {py_time/np_time:.0f}x")
19# NumPy nhanh hơn: ~50-100x

Tại sao NumPy nhanh?

3 lý do NumPy nhanh hơn Python list:

  1. Contiguous Memory: Dữ liệu lưu liên tục trong bộ nhớ → cache-friendly
  2. Fixed dtype: Tất cả phần tử cùng kiểu → không cần type checking
  3. C Backend: Vòng lặp chạy bằng C, không phải Python interpreter

NumPy trong Hệ sinh thái Data Science

NumPy trong Hệ sinh thái Data Science

🔢NumPy (nền tảng)
🐼Pandas (DataFrame)
📊Matplotlib/Seaborn (Visualization)
🤖Scikit-learn (Machine Learning)
🧠TensorFlow/PyTorch (Deep Learning)
🔬SciPy (Scientific Computing)

Checkpoint

Bạn có hiểu tại sao np.array([1,2,3]) * 2 nhanh hơn [x*2 for x in [1,2,3]] không?

3

🧱 Tạo và Khởi tạo Array

TB5 min

Từ Python list

Python
1import numpy as np
2
3# 1D array
4a = np.array([1, 2, 3, 4, 5])
5print(a, type(a)) # [1 2 3 4 5] <class 'numpy.ndarray'>
6
7# 2D array (ma trận)
8b = np.array([[1, 2, 3],
9 [4, 5, 6]])
10print(b.shape) # (2, 3) — 2 hàng, 3 cột
11print(b.dtype) # int64
12print(b.ndim) # 2 chiều
13print(b.size) # 6 phần tử

Hàm khởi tạo thường dùng

Python
1# Mảng 0 và 1
2zeros = np.zeros((3, 4)) # Ma trận 3x4 toàn 0
3ones = np.ones((2, 3)) # Ma trận 2x3 toàn 1
4full = np.full((2, 2), 7) # Ma trận 2x2 toàn 7
5
6# Dãy số
7arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8] — giống range()
8linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0] — chia đều
9
10# Ma trận đơn vị
11eye = np.eye(3) # Ma trận đơn vị 3x3
12
13# Random
14rand = np.random.rand(3, 3) # Uniform [0, 1)
15randn = np.random.randn(3, 3) # Normal (mean=0, std=1)
16randint = np.random.randint(1, 100, (3, 3)) # Integer [1, 100)

Chọn dtype phù hợp để tiết kiệm bộ nhớ:

  • np.float32 thay vì float64 → tiết kiệm 50% RAM
  • np.int16 cho số nhỏ (dưới 32768)
  • np.bool_ cho mảng True/False
Python
1# Chỉ định dtype
2a = np.array([1, 2, 3], dtype=np.float32)
3print(a.nbytes) # 12 bytes (thay vì 24 với float64)

Checkpoint

Tạo ma trận 5x5 với giá trị random từ 0-100 (integer). Gợi ý: np.random.randint()

4

🔍 Indexing và Slicing

TB5 min

Indexing là gì? Là cách truy cập phần tử cụ thể trong mảng theo vị trí. Slicing là cách cắt một phần của mảng.

Tại sao quan trọng? Trong Data Science, bạn thường cần: lấy 100 dòng đầu tiên, chọn cột cụ thể, lọc dữ liệu theo điều kiện — tất cả đều là indexing/slicing.

Basic Indexing (1D)

Python
1a = np.array([10, 20, 30, 40, 50])
2
3print(a[0]) # 10 — phần tử đầu
4print(a[-1]) # 50 — phần tử cuối
5print(a[1:4]) # [20, 30, 40] — slice
6print(a[::2]) # [10, 30, 50] — step=2

2D Indexing

Python
1matrix = np.array([[1, 2, 3],
2 [4, 5, 6],
3 [7, 8, 9]])
4
5print(matrix[0, 1]) # 2 — hàng 0, cột 1
6print(matrix[1]) # [4, 5, 6] — toàn bộ hàng 1
7print(matrix[:, 0]) # [1, 4, 7] — toàn bộ cột 0
8print(matrix[0:2, 1:]) # [[2, 3], [5, 6]] — sub-matrix

Boolean Indexing (Rất quan trọng!)

Python
1scores = np.array([85, 92, 78, 95, 68, 88, 73])
2
3# Mask: mảng True/False
4passed = scores >= 80
5print(passed) # [True True False True False True False]
6
7# Lọc bằng boolean mask
8print(scores[passed]) # [85 92 95 88]
9
10# Thay đổi giá trị theo điều kiện
11scores[scores < 80] = 80 # Nâng điểm "sàn" lên 80
12print(scores) # [85 92 80 95 80 88 80]

Fancy Indexing

Python
1a = np.array([10, 20, 30, 40, 50])
2
3# Chọn nhiều phần tử bằng list index
4print(a[[0, 2, 4]]) # [10, 30, 50]
5print(a[[3, 1, 4]]) # [40, 20, 50] — thứ tự tùy ý
6
7# np.where — tìm vị trí thỏa điều kiện
8idx = np.where(a > 25)
9print(idx) # (array([2, 3, 4]),)
10print(a[idx]) # [30, 40, 50]

View vs Copy: Slicing trả về view (tham chiếu), không phải copy!

Python
1a = np.array([1, 2, 3, 4, 5])
2b = a[1:4] # b là view
3b[0] = 99
4print(a) # [1, 99, 3, 4, 5] — a cũng bị thay đổi!
5
6# Muốn copy? Dùng .copy()
7c = a[1:4].copy()
8c[0] = 0
9print(a) # [1, 99, 3, 4, 5] — a không đổi

Checkpoint

Cho arr = np.arange(20).reshape(4,5). Lấy ra tất cả phần tử chẵn ở cột cuối cùng.

5

🔄 Reshape và Manipulation

TB5 min

Reshape là gì? Là thay đổi hình dạng mảng mà không thay đổi dữ liệu. Ví dụ: mảng 12 phần tử có thể thành 3x4, 4x3, 2x6...

Tại sao cần reshape? Nhiều model ML yêu cầu input có shape cụ thể. Ví dụ: ảnh 28x28 pixel cần reshape thành 784 phần tử để đưa vào Neural Network, hoặc ngược lại.

Reshape — Thay đổi hình dạng

Python
1a = np.arange(12)
2print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11]
3
4# Reshape sang 3x4
5b = a.reshape(3, 4)
6print(b)
7# [[ 0 1 2 3]
8# [ 4 5 6 7]
9# [ 8 9 10 11]]
10
11# -1: tự tính chiều còn lại
12c = a.reshape(2, -1) # 2 hàng, NumPy tự tính 6 cột
13print(c.shape) # (2, 6)
14
15# Flatten: về 1D
16print(b.ravel()) # [ 0 1 2 ... 11] — view
17print(b.flatten()) # [ 0 1 2 ... 11] — copy

Nối và Tách mảng

Python
1a = np.array([1, 2, 3])
2b = np.array([4, 5, 6])
3
4# Nối
5print(np.concatenate([a, b])) # [1 2 3 4 5 6]
6
7# Stack
8x = np.array([[1, 2], [3, 4]])
9y = np.array([[5, 6], [7, 8]])
10
11print(np.vstack([x, y])) # Nối dọc → shape (4, 2)
12print(np.hstack([x, y])) # Nối ngang → shape (2, 4)
13
14# Tách
15arr = np.arange(12).reshape(3, 4)
16a, b, c = np.split(arr, 3, axis=0) # Tách theo hàng

Transpose

Python
1m = np.array([[1, 2, 3],
2 [4, 5, 6]])
3print(m.T) # Chuyển vị
4# [[1, 4],
5# [2, 5],
6# [3, 6]]
7print(m.T.shape) # (3, 2)

Checkpoint

Tạo mảng 1D gồm 24 phần tử, reshape thành (2, 3, 4). In shape và tổng theo từng axis.

6

📡 Broadcasting

TB5 min

Quy tắc Broadcasting

Khi thực hiện phép tính giữa 2 mảng khác shape, NumPy tự mở rộng mảng nhỏ:

3 quy tắc Broadcasting:

  1. Nếu 2 mảng khác số chiều → thêm chiều 1 ở bên trái mảng nhỏ
  2. Nếu kích thước ở 1 chiều khác nhau → mảng có size=1 được stretch theo chiều đó
  3. Nếu kích thước khác nhau mà KHÔNG có size=1 → LỖI

Ví dụ minh họa

Python
1# Scalar + Array (phổ biến nhất)
2a = np.array([1, 2, 3])
3print(a + 10) # [11, 12, 13]
4print(a * 2) # [2, 4, 6]
5
6# Vector + Matrix
7matrix = np.array([[1, 2, 3],
8 [4, 5, 6],
9 [7, 8, 9]])
10row = np.array([10, 20, 30])
11
12print(matrix + row)
13# [[11, 22, 33],
14# [14, 25, 36],
15# [17, 28, 39]]
16
17# Column vector + Matrix
18col = np.array([[100], [200], [300]])
19print(matrix + col)
20# [[101, 102, 103],
21# [204, 205, 206],
22# [307, 308, 309]]

Ứng dụng: Chuẩn hóa dữ liệu

Python
1# Z-score normalization (rất quan trọng trong ML!)
2data = np.array([[170, 60], # Chiều cao (cm), Cân nặng (kg)
3 [180, 75],
4 [165, 55],
5 [175, 68]])
6
7mean = data.mean(axis=0) # [172.5, 64.5]
8std = data.std(axis=0) # [5.59, 7.63]
9
10normalized = (data - mean) / std # Broadcasting!
11print(normalized.round(2))
12# [[-0.45, -0.59],
13# [ 1.34, 1.38],
14# [-1.34, -1.25],
15# [ 0.45, 0.46]]

Mẹo debug broadcasting: Dùng np.broadcast_shapes() để kiểm tra:

Python
1np.broadcast_shapes((3, 1), (1, 4)) # → (3, 4) ✅
2np.broadcast_shapes((3,), (4,)) # → Error ❌

Checkpoint

Giải thích tại sao np.ones((3,1)) + np.ones((1,4)) cho kết quả shape (3,4)?

7

📊 Hàm Toán học và Thống kê

TB5 min

Tại sao cần hàm thống kê? Khi phân tích dữ liệu, bạn luôn cần biết: dữ liệu trung bình bao nhiêu? (mean), giá trị nào xuất hiện giữa? (median), dữ liệu phân tán ra sao? (std), giá trị cực đại/tiểu? (min, max). NumPy tính các giá trị này nhanh gấp trăm lần so với Python thuần.

Toán học cơ bản (Element-wise)

Python
1a = np.array([1, 4, 9, 16, 25])
2
3print(np.sqrt(a)) # [1. 2. 3. 4. 5.]
4print(np.square(a)) # [1 16 81 256 625]
5print(np.log(a)) # [0. 1.39 2.20 2.77 3.22]
6print(np.exp([1,2])) # [2.718 7.389]
7print(np.abs([-3,2])) # [3 2]

Thống kê

Python
1scores = np.array([85, 92, 78, 95, 68, 88, 73, 91, 82, 96])
2
3print(f"Mean: {np.mean(scores):.1f}") # 84.8
4print(f"Median: {np.median(scores):.1f}") # 86.5
5print(f"Std: {np.std(scores):.1f}") # 8.8
6print(f"Var: {np.var(scores):.1f}") # 78.0
7print(f"Min: {np.min(scores)}") # 68
8print(f"Max: {np.max(scores)}") # 96
9print(f"Sum: {np.sum(scores)}") # 848
10
11# Vị trí min/max
12print(f"ArgMin: {np.argmin(scores)}") # 4 (index của 68)
13print(f"ArgMax: {np.argmax(scores)}") # 9 (index của 96)
14
15# Percentile
16print(f"P25: {np.percentile(scores, 25):.1f}") # 77.0
17print(f"P75: {np.percentile(scores, 75):.1f}") # 91.75

Thống kê theo Axis

Axis là gì? Khi có dữ liệu 2D (bảng), axis=0 tính theo cột (dọc xuống — mỗi môn học), axis=1 tính theo hàng (ngang qua — mỗi sinh viên). Đây là khái niệm bạn sẽ dùng hàng ngày trong Pandas!

Python
1data = np.array([[85, 90, 78], # Student 1
2 [92, 88, 95], # Student 2
3 [76, 85, 80]]) # Student 3
4# Columns: Math, Physics, Chemistry
5
6# Trung bình theo hàng (mỗi sinh viên)
7print(np.mean(data, axis=1)) # [84.33 91.67 80.33]
8
9# Trung bình theo cột (mỗi môn)
10print(np.mean(data, axis=0)) # [84.33 87.67 84.33]

Đại số tuyến tính

Tại sao cần? Nhiều thuật toán ML (Linear Regression, PCA, Neural Networks) đều dựa trên phép nhân ma trận. Bạn không cần thạo mối lắm về đại số tuyến tính — chỉ cần biết các hàm cơ bản:

Python
1# Dot product
2a = np.array([1, 2, 3])
3b = np.array([4, 5, 6])
4print(np.dot(a, b)) # 32 = 1*4 + 2*5 + 3*6
5
6# Matrix multiplication
7A = np.array([[1, 2], [3, 4]])
8B = np.array([[5, 6], [7, 8]])
9print(A @ B) # [[19 22], [43 50]] — toán tử @
10print(np.matmul(A, B)) # Tương đương
11
12# Determinant và Inverse
13print(np.linalg.det(A)) # -2.0
14print(np.linalg.inv(A)) # [[-2, 1], [1.5, -0.5]]

Checkpoint

Cho ma trận điểm 100 sinh viên × 5 môn (random 0-100). Tính: điểm TB mỗi môn, sinh viên điểm cao nhất, và số sinh viên dưới trung bình.

8

🎲 Random & Reproducibility

TB5 min

np.random — Sinh số ngẫu nhiên

Python
1# Seed: đảm bảo kết quả lặp lại
2np.random.seed(42)
3
4# Uniform distribution [0, 1)
5print(np.random.rand(3)) # [0.374 0.950 0.731]
6
7# Normal distribution (Gaussian)
8print(np.random.randn(3)) # [-0.256 0.840 -0.264]
9
10# Custom range
11print(np.random.uniform(10, 20, 5)) # 5 số từ 10-20
12print(np.random.normal(100, 15, 5)) # 5 số, mean=100, std=15
13print(np.random.randint(1, 7, 10)) # 10 lần tung xúc xắc
14
15# Random choice
16items = ["A", "B", "C", "D"]
17print(np.random.choice(items, 3, replace=True)) # Có lặp
18print(np.random.choice(items, 3, replace=False)) # Không lặp

Modern Random (Recommended)

Python
1# Cách mới: dùng Generator (NumPy ≥ 1.17)
2rng = np.random.default_rng(seed=42)
3
4print(rng.random(5)) # 5 số uniform
5print(rng.normal(0, 1, 5)) # 5 số normal
6print(rng.integers(1, 100, 5)) # 5 số integer
7
8# Shuffle
9arr = np.arange(10)
10rng.shuffle(arr)
11print(arr) # Xáo trộn ngẫu nhiên

Luôn set seed khi viết code Data Science/ML để kết quả reproducible:

Python
1np.random.seed(42)
2# hoặc
3rng = np.random.default_rng(42)

Checkpoint

Mô phỏng tung 2 xúc xắc 10,000 lần. Đếm số lần tổng = 7. Xác suất lý thuyết là 6/36 = 16.67%.

9

📝 Tổng Kết

TB5 min

Tóm tắt kiến thức

Chủ đềHàm/Khái niệm chính
Tạo arraynp.array(), zeros(), ones(), arange(), linspace()
Indexinga[0], a[1:4], a[mask], np.where()
Reshapereshape(), ravel(), flatten(), T
BroadcastingScalar ↔ Array, Vector ↔ Matrix
Math/Statsmean(), std(), sum(), median(), percentile()
Linear Algebradot(), @, linalg.inv(), linalg.det()
Randomseed(), rand(), randn(), choice(), default_rng()

Quick Reference

Python
1import numpy as np
2
3# Tạo
4a = np.array([1, 2, 3])
5m = np.zeros((3, 4))
6
7# Thuộc tính
8a.shape, a.dtype, a.ndim, a.size
9
10# Thao tác
11a.reshape(1, -1) # → (1, 3)
12a[a > 1] # Boolean indexing
13np.concatenate() # Nối
14np.vstack/hstack() # Stack
15
16# Toán
17np.mean(a), np.std(a), np.sum(a)
18a @ b # Matrix multiply

Bài tiếp theo: Thực hành NumPy với các bài tập từ cơ bản đến nâng cao! 🎯

Câu hỏi tự kiểm tra

  1. NumPy array khác gì so với Python list? Tại sao NumPy nhanh hơn nhiều lần?
  2. Broadcasting trong NumPy là gì? Cho ví dụ khi cộng một scalar với một array.
  3. Boolean indexing hoạt động như thế nào? Viết cách lọc các phần tử lớn hơn 5 trong array.
  4. Tại sao cần set np.random.seed() khi viết code Data Science/ML?

🎉 Tuyệt vời! Bạn đã hoàn thành bài học NumPy!

Tiếp theo: Thực hành NumPy với các bài tập từ cơ bản đến nâng cao để củng cố kiến thức!