Danh sách bài viết

Bài 4: Scikit-Learn (sklearn) — thư viện chuẩn ngành cho ML cổ điển

Giới thiệu Scikit-Learn: triết lý API thống nhất (fit/predict/transform), cấu trúc submodule, quy ước input X/y, random_state, hyperparameter vs parameter và những gì sklearn KHÔNG làm.

24/05/2026
13 phút đọc
0 lượt xem
1

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

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

  • Biết sklearn là gì, ai phát triển và vị trí trong ecosystem ML Python.
  • Hiểu triết lý API thống nhất: fit / predict / transform dùng cho mọi model.
  • Nhớ được các submodule chính và biết tra cứu thuộc nhóm nào.
  • Viết được workflow 5 dòng: load data → split → fit → score.
  • Phân biệt được hyperparameter và parameter, hiểu vai trò random_state.
  • Biết giới hạn của sklearn để chọn công cụ phù hợp khi gặp deep learning hoặc dữ liệu lớn.
2

Scikit-Learn là gì

Scikit-Learn (gọi tắt là sklearn) là thư viện Machine Learning cổ điển open-source viết bằng Python, build trên nền NumPy, SciPy và một phần Cython để tăng tốc.

Lịch sử ngắn:

  • 2007: David Cournapeau khởi tạo dự án trong khuôn khổ Google Summer of Code, ban đầu tên scikits.learn (một SciKit của SciPy).
  • 2010: nhóm tại INRIA (Pháp) — đặc biệt Fabian Pedregosa, Gaël Varoquaux, Alexandre Gramfort — phát hành public version đầu tiên.
  • Từ đó tới nay duy trì bởi INRIA + cộng đồng, được Google, Microsoft, Quansight, Nvidia... tài trợ qua các grant.
  • Paper gốc thường được trích dẫn: Pedregosa et al. (2011) — "Scikit-learn: Machine Learning in Python" trên JMLR.

Vị trí trong ecosystem:

  • Sklearn lo phần ML cổ điển: linear/logistic regression, tree, ensemble, SVM, KNN, clustering, PCA, preprocessing, pipeline, model selection.
  • Deep Learning (mạng nhiều tầng, GPU) thuộc về PyTorch / TensorFlow — sẽ học ở Series 3.
  • LLM / Generative AI là một hướng khác hoàn toàn — Series 4.

Bài này dùng sklearn 1.5+ (bản phát hành 2024-2025). Một số API cũ (như load_boston) đã bị remove vì lý do đạo đức dữ liệu; sách / blog cũ trước 2022 cần đọc kèm changelog.

3

Cài đặt và import

Cài đặt:

pip install scikit-learn

# Hoặc dùng conda
conda install -c conda-forge scikit-learn

Google Colab, Kaggle Notebook, Jupyter image của jupyter/scipy-notebook đều có sẵn sklearn — không cần cài lại.

Kiểm tra version:

import sklearn
print(sklearn.__version__)
# Ví dụ output: 1.5.2

Convention import: sklearn không có alias chuẩn như np hay pd. Mọi thứ import theo dạng from sklearn.<submodule> import <Class>:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score

Tránh viết import sklearn rồi gọi sklearn.linear_model.LogisticRegression(...) — dài và không phổ biến trong code thực tế.

4

Triết lý sklearn — API thống nhất

Điểm mạnh lớn nhất của sklearn không nằm ở số lượng thuật toán, mà ở consistent API: mọi object đều tuân theo cùng một bộ method. Nắm 3 interface dưới đây là dùng được hầu hết thư viện.

1. Estimator interface (model)

Mọi model dự đoán đều có:

  • .fit(X, y) — train model trên dữ liệu.
  • .predict(X) — sinh dự đoán cho dữ liệu mới.
  • .score(X, y) — đánh giá nhanh trên test set (accuracy cho classifier, R² cho regressor).
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(X_train, y_train)       # train
y_pred = model.predict(X_test)    # predict
acc = model.score(X_test, y_test) # đánh giá

2. Transformer interface (preprocessor)

Các đối tượng biến đổi dữ liệu (scaler, encoder, PCA...) có:

  • .fit(X) — học thông số từ data (vd: mean, std).
  • .transform(X) — áp dụng biến đổi.
  • .fit_transform(X) — shortcut: fit rồi transform luôn trên cùng tập.
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # học mean/std trên train
X_test_scaled = scaler.transform(X_test)        # chỉ transform, KHÔNG fit lại

Quy tắc vàng: fit trên train, transform trên cả train và test. Fit lại trên test sẽ leak thông tin và làm metric không trung thực.

3. Predictor cho unsupervised

Một số model unsupervised (vd KMeans) vừa là estimator vừa là transformer:

from sklearn.cluster import KMeans

km = KMeans(n_clusters=3, random_state=42)
km.fit(X)
labels = km.predict(X)         # gán cluster
distances = km.transform(X)    # khoảng cách tới mỗi centroid

Vì cùng một bộ method, việc swap model chỉ là đổi tên class — không cần viết lại pipeline. Đây là lý do sklearn dễ học và dễ thử nghiệm.

5

Cấu trúc thư viện — các submodule chính

Sklearn tổ chức theo submodule — biết tên submodule là biết tra ở đâu:

Submodule Mục đích Ví dụ object
sklearn.datasets Load dataset built-in / fetch dataset chuẩn load_iris, load_digits, fetch_california_housing
sklearn.model_selection Chia train/test, cross-validation, tìm hyperparameter train_test_split, KFold, GridSearchCV
sklearn.preprocessing Scaling, encoding, biến đổi feature StandardScaler, MinMaxScaler, OneHotEncoder
sklearn.linear_model Linear/logistic regression và biến thể regularized LinearRegression, LogisticRegression, Ridge, Lasso
sklearn.tree Decision tree DecisionTreeClassifier, DecisionTreeRegressor
sklearn.ensemble Bagging, boosting, voting RandomForestClassifier, GradientBoostingRegressor
sklearn.cluster Clustering unsupervised KMeans, DBSCAN, AgglomerativeClustering
sklearn.decomposition Giảm chiều PCA, TruncatedSVD, NMF
sklearn.metrics Hàm đo accuracy, MSE, F1, ROC... accuracy_score, mean_squared_error, classification_report
sklearn.pipeline Ghép preprocessor + model thành một estimator duy nhất Pipeline, make_pipeline

Còn nhiều submodule khác (neighbors, svm, naive_bayes, feature_selection, impute...). Khi cần một thuật toán, hỏi: "thuật toán này thuộc nhóm gì?" rồi vào submodule tương ứng tra cứu.

Lưu ý: load_boston đã bị remove từ sklearn 1.2 vì vấn đề đạo đức dữ liệu (biến chủng tộc trong feature). Dùng fetch_california_housing hoặc fetch_openml('ames_housing') thay thế cho bài tập regression giá nhà.

6

Quy ước input X và y

Mọi API sklearn đều giả định input có dạng cố định:

  • X: ma trận feature, shape (n_samples, n_features) — luôn 2 chiều, kể cả khi chỉ có 1 feature.
  • y: vector label / target, shape (n_samples,) — 1 chiều cho single-output; (n_samples, n_outputs) cho multi-output.

Hỗ trợ cả NumPy array và Pandas DataFrame. Sklearn nội bộ sẽ chuyển DataFrame sang NumPy khi cần, nhưng giữ thông tin tên cột để báo lỗi rõ ràng hơn.

import numpy as np
import pandas as pd

# Cách 1: NumPy
X = np.array([[5.1, 3.5], [4.9, 3.0], [6.2, 3.4]])
y = np.array([0, 0, 1])
print(X.shape)  # (3, 2)
print(y.shape)  # (3,)

# Cách 2: Pandas DataFrame / Series
df = pd.DataFrame(X, columns=['sepal_length', 'sepal_width'])
target = pd.Series(y, name='species')
# model.fit(df, target) hoạt động bình thường

Lỗi thường gặp: đưa vào X 1 chiều khi chỉ có 1 feature.

X_wrong = np.array([1, 2, 3, 4])        # shape (4,) — SAI
X_right = np.array([[1], [2], [3], [4]]) # shape (4, 1) — ĐÚNG
# hoặc dùng reshape
X_right = np.array([1, 2, 3, 4]).reshape(-1, 1)
7

Workflow chuẩn — 5 dòng code

Để cảm nhận sự gọn gàng của sklearn, đây là một classification workflow hoàn chỉnh trên dataset Iris:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

# 1. Load data
X, y = load_iris(return_X_y=True)

# 2. Chia train / test
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 3. Khởi tạo + train + đánh giá
model = LogisticRegression(max_iter=1000).fit(X_train, y_train)
print(f"Test accuracy: {model.score(X_test, y_test):.4f}")
# Output ví dụ: Test accuracy: 1.0000

Phân tích nhanh:

  • return_X_y=True trả về thẳng tuple (X, y) thay vì object Bunch — tiện cho code ngắn.
  • test_size=0.2 giữ 20% cho test (32 mẫu trên 150).
  • max_iter=1000 tăng số iteration solver vì mặc định 100 đôi khi không đủ converge — sklearn sẽ warning nếu thiếu.
  • .fit().score() chain được vì .fit() trả về self theo convention.

In thêm tên feature và label để hiểu data:

data = load_iris()
print("Feature names:", data.feature_names)
# ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

print("Target names:", data.target_names)
# ['setosa' 'versicolor' 'virginica']

print("X shape:", data.data.shape, "y shape:", data.target.shape)
# X shape: (150, 4) y shape: (150,)
8

random_state và reproducibility

Rất nhiều function / class trong sklearn dùng số ngẫu nhiên: train_test_split trộn dữ liệu, RandomForest chọn feature ngẫu nhiên, KMeans khởi tạo centroid ngẫu nhiên...

Tham số random_state điều khiển bộ sinh số ngẫu nhiên. Cùng random_state → cùng kết quả khi chạy lại.

from sklearn.model_selection import train_test_split

# random_state = None (mặc định): mỗi lần chạy ra split khác nhau
X1, X2, y1, y2 = train_test_split(X, y, test_size=0.2)

# random_state = 42: chạy 100 lần vẫn ra cùng kết quả
X1, X2, y1, y2 = train_test_split(X, y, test_size=0.2, random_state=42)

Vì sao 42? Quy ước cộng đồng (joke từ Hitchhiker's Guide to the Galaxy). Số nào cũng được — quan trọng là phải cố định trong report và bài tập để người khác reproduce được kết quả.

Lưu ý: reproducibility tuyệt đối còn phụ thuộc version sklearn, NumPy, BLAS backend, OS. Cùng random_state trên 2 máy đôi khi vẫn lệch ở chữ số thập phân thứ 6-7 — chấp nhận được cho lab; cần lock chặt cho production.

9

Hyperparameter vs Parameter

Hai khái niệm dễ nhầm:

  • Hyperparameter: tham số do người dùng set khi tạo estimator. Vd: C của Logistic Regression, n_estimators của Random Forest, n_clusters của KMeans.
  • Parameter (weight, coefficient): giá trị model học từ data trong .fit(). Vd: coef_intercept_ của Linear Regression.
from sklearn.linear_model import LogisticRegression

# C, max_iter, solver — hyperparameter (đặt trước khi fit)
model = LogisticRegression(C=1.0, max_iter=1000, solver='lbfgs')
model.fit(X_train, y_train)

# coef_, intercept_ — parameter (học từ data, kết thúc bằng _)
print("coef_ shape:", model.coef_.shape)
print("intercept_:", model.intercept_)

Quy ước đặt tên: mọi thuộc tính kết thúc bằng dấu gạch dưới (coef_, feature_importances_, classes_) là parameter học được sau khi fit — truy cập trước khi fit sẽ raise NotFittedError.

Hyperparameter tuning (Grid Search, Random Search) là chủ đề riêng — sẽ học ở Module 6 cuối series.

10

Estimator clone

Khi cần một estimator cùng cấu hình nhưng chưa fit (vd để train trên fold khác trong cross-validation, hoặc thử cấu hình giống hệt trên dataset khác), dùng clone:

from sklearn.base import clone
from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)

# clone tạo bản copy: cùng hyperparameter, KHÔNG copy weight đã fit
rf_fresh = clone(rf)
print(hasattr(rf, 'classes_'))        # True — đã fit
print(hasattr(rf_fresh, 'classes_'))  # False — chưa fit

Phân biệt với copy.deepcopy: deepcopy sao chép cả trạng thái đã train (weight, classes_); clone chỉ giữ cấu hình. Cross-validation nội bộ của sklearn dùng clone.

11

Những gì sklearn KHÔNG làm

Biết giới hạn quan trọng không kém biết tính năng:

  • Không có deep learning. Sklearn có MLPClassifier đơn giản nhưng không phải framework DL. Mạng CNN, RNN, Transformer phải dùng PyTorch hoặc TensorFlow (Series 3).
  • Không có GPU support trực tiếp. Toàn bộ sklearn chạy trên CPU (single-host, multi-core qua n_jobs). Nếu cần GPU cho thuật toán cổ điển, có cuML của Nvidia RAPIDS — API gần giống sklearn nhưng chạy GPU.
  • Không cho dataset out-of-memory. Sklearn giả định dữ liệu fit hết vào RAM. Khi dataset hàng chục GB, dùng Dask-ML, Vaex, hoặc partial_fit của một số estimator (SGDClassifier, MiniBatchKMeans).
  • Không phải reinforcement learning library. RL có ecosystem riêng: Stable-Baselines3, RLlib, CleanRL.
  • Không tự làm feature engineering domain-specific (text, ảnh, time-series phức tạp). Có module hỗ trợ cơ bản nhưng cần thư viện chuyên: nltk/spacy cho text, opencv/PIL cho ảnh, statsmodels/prophet cho time-series.

Khi gặp bài toán vượt giới hạn này, chuyển công cụ chứ không cố ép sklearn.

12

Tài nguyên học tập

  • User Guide tại scikit-learn.org/stable/user_guide.html — viết kỹ, có lý thuyết kèm code; nên đọc mỗi khi gặp model mới.
  • API Reference tại scikit-learn.org/stable/api/ — tra cứu signature và parameter từng class.
  • Examples gallery tại scikit-learn.org/stable/auto_examples/ — code mẫu kèm hình vẽ, copy chạy được.
  • Sách: "Hands-On Machine Learning with Scikit-Learn, Keras & TensorFlow" — Aurélien Géron (O'Reilly, 3rd ed. 2022).
  • Khóa MOOC chính chủ: "scikit-learn MOOC" của INRIA, miễn phí, có exercise.

Khi tra Stack Overflow / blog, lưu ý version. Code từ 2018-2020 có thể dùng API đã thay đổi (vd sklearn.cross_validation đã đổi thành sklearn.model_selection; load_boston đã remove).

13

Bài tập thực hành

Bài 1: Load dataset digits từ sklearn.datasets. In shape của Xy, số class, và 1-2 dòng đầu của X.

# Gợi ý
from sklearn.datasets import load_digits
data = load_digits()
# Hoàn thiện in shape, target_names, ...

Bài 2: Train LogisticRegression trên iris với random_state=0random_state=42. So sánh test accuracy giữa hai lần split. Giải thích vì sao có thể khác nhau dù cùng model.

Bài 3: Mở scikit-learn.org/stable/api/sklearn.linear_model.html (hoặc dùng dir(sklearn.linear_model)) và liệt kê 3 estimator khác ngoài LinearRegression / LogisticRegression. Ghi 1 câu giải thích từng cái (vd Ridge = linear regression có L2 regularization).

Bài 4 (nâng cao): Thay LogisticRegression trong workflow ở mục 7 bằng RandomForestClassifier(n_estimators=100, random_state=42). Quan sát: code phía ngoài có cần đổi gì không? (Trả lời ngắn: gần như không — đây chính là điểm mạnh của consistent API).

Gợi ý đáp án bài 2: hai random_state khác → train_test_split trả về hai cách chia khác → tập train / test có sample khác nhau → model học khác → score khác. Đây là lý do production đánh giá bằng cross-validation chứ không chỉ một split duy nhất.

14

Bài tiếp theo

Bài 5: Dataset đầu tiên — load_iris và làm quen với feature / label — mổ xẻ chi tiết dataset Iris (150 hoa, 4 feature, 3 loài), xem từng cột nghĩa là gì và thực hành visualize trước khi train.