Python cho Data Science: NumPy, Pandas và Scikit-Learn trong năm 2026
Hướng dẫn thực hành NumPy 2.1, Pandas 2.2 và Scikit-Learn 1.6 với Python 3.12. Từ làm sạch dữ liệu, Feature Engineering đến xây dựng ML Pipeline sẵn sàng triển khai — kèm đầy đủ ví dụ mã nguồn.

Python tiếp tục giữ vị thế là ngôn ngữ chủ đạo trong lĩnh vực Data Science vào năm 2026 — không phải nhờ các xu hướng nhất thời, mà nhờ hệ sinh thái trưởng thành xung quanh ba thư viện cốt lõi: NumPy, Pandas và Scikit-Learn. NumPy cung cấp các phép toán ma trận hiệu năng cao, Pandas hỗ trợ thao tác dữ liệu dạng bảng linh hoạt, và Scikit-Learn mang đến các thuật toán Machine Learning sẵn sàng sử dụng. Thành thạo ba công cụ này cho phép người làm việc với dữ liệu thực hiện toàn bộ quy trình từ xử lý dữ liệu thô đến triển khai mô hình hoàn toàn trong Python. Bài viết này trình bày một ví dụ xuyên suốt — phân tích và dự đoán việc thăng chức nhân viên — để minh họa cách sử dụng hiệu quả cả ba thư viện.
Tất cả các đoạn mã trong bài viết được phát triển và kiểm thử với Python 3.12+, NumPy 2.1, Pandas 2.2 và Scikit-Learn 1.6. Các phiên bản cũ hơn có thể khác biệt ở một số chi tiết API, đặc biệt là hành vi Copy-on-Write của Pandas 2.2 và các tính năng tương thích Array API mới trong NumPy 2.1.
Các phép toán mảng NumPy: Cơ bản và Boolean Indexing
NumPy thay thế danh sách Python và các vòng lặp truyền thống bằng các phép toán vector hóa (vectorized operations), được thực thi bên dưới bằng mã C tối ưu. Thay vì sử dụng vòng lặp for để duyệt từng phần tử, các hàm NumPy hoạt động trên toàn bộ mảng cùng lúc — mang lại tốc độ nhanh hơn từ 10 đến 100 lần so với Python thuần trong các tác vụ Data Science điển hình.
Ví dụ dưới đây minh họa các thao tác mảng cơ bản: tạo mảng từ danh sách, phép tính số học vector hóa, và kỹ thuật Boolean Indexing quan trọng giúp lọc dữ liệu mà không cần vòng lặp.
# numpy_basics.py
import numpy as np
# Create arrays from different sources
prices = np.array([29.99, 49.99, 19.99, 99.99, 39.99])
quantities = np.arange(1, 6) # [1, 2, 3, 4, 5]
# Vectorized arithmetic — no loops needed
revenue = prices * quantities
print(revenue) # [29.99, 99.98, 59.97, 399.96, 199.95]
# Statistical aggregations
print(f"Total revenue: ${revenue.sum():.2f}") # $789.85
print(f"Mean price: ${prices.mean():.2f}") # $47.99
print(f"Std deviation: ${prices.std():.2f}") # $27.64
# Boolean indexing — filter without loops
premium_mask = prices > 40
premium_items = prices[premium_mask] # [49.99, 99.99]Boolean Indexing là một mẫu thiết kế trung tâm trong NumPy: biểu thức prices > 40 tạo ra một mảng gồm các giá trị True/False, đóng vai trò trực tiếp như một bộ lọc (mask). Khái niệm này sẽ xuất hiện lại trong Pandas DataFrame, bởi Pandas được xây dựng trên nền tảng NumPy. Các hàm thống kê tổng hợp — sum(), mean(), std() — mặc định hoạt động trên toàn bộ phần tử; thông qua tham số axis, chúng có thể được điều chỉnh để tính toán theo chiều cụ thể trên mảng đa chiều.
Reshape và Broadcasting trong NumPy
Mảng đa chiều xuất hiện phổ biến trong thực tế: dữ liệu doanh số theo sản phẩm và tháng, giá trị pixel trong hình ảnh, hoặc ma trận đặc trưng (feature matrix) cho các mô hình Machine Learning. NumPy cho phép biến đổi linh hoạt cấu trúc dữ liệu thông qua reshape(), đồng thời hỗ trợ broadcasting tự động khi thực hiện phép tính giữa các mảng có kích thước khác nhau.
# numpy_reshape.py
import numpy as np
# Monthly sales data: 4 products x 3 months
sales = np.array([
[120, 150, 130], # Product A
[200, 180, 220], # Product B
[90, 110, 95], # Product C
[300, 280, 310], # Product D
])
# Column-wise mean (average per month)
monthly_avg = sales.mean(axis=0) # [177.5, 180.0, 188.75]
# Row-wise sum (total per product)
product_totals = sales.sum(axis=1) # [400, 600, 295, 890]
# Normalize each product relative to its own max
normalized = sales / sales.max(axis=1, keepdims=True)
# keepdims=True preserves the shape for broadcasting
print(normalized[0]) # [0.8, 1.0, 0.867] — Product A relative to its peak
# Reshape for Scikit-Learn (requires 2D input)
flat_sales = sales.flatten() # 1D array of 12 values
reshaped = flat_sales.reshape(-1, 1) # 12x1 column vectorTham số axis đóng vai trò quyết định: axis=0 tổng hợp theo cột (qua các hàng), axis=1 tổng hợp theo hàng (qua các cột). Khi chuẩn hóa với keepdims=True, shape (4, 1) được giữ nguyên, đảm bảo broadcasting hoạt động chính xác trong phép chia. Biểu thức reshape(-1, 1) ở cuối là một mẫu thường gặp: Scikit-Learn luôn yêu cầu đầu vào ít nhất là mảng 2D.
Thao tác và làm sạch dữ liệu với Pandas DataFrame
Pandas là công cụ chính để xử lý dữ liệu dạng bảng trong Python. Một DataFrame hoạt động tương tự như bảng cơ sở dữ liệu hoặc bảng tính Excel, nhưng cung cấp khả năng biến đổi mạnh mẽ hơn nhiều. Trong thực tế, làm sạch dữ liệu là bước tốn thời gian nhất của mọi dự án Data Science — các giá trị thiếu, ngoại lai, trùng lặp và kiểu dữ liệu không nhất quán đều cần được xử lý có hệ thống.
Cách tiếp cận được khuyến nghị là xây dựng một chuỗi biến đổi có thể tái tạo (reproducible), giữ nguyên DataFrame gốc và lưu kết quả vào biến mới. Ví dụ dưới đây làm việc với tập dữ liệu gồm 1.500 hồ sơ ứng viên.
# pandas_cleaning.py
import pandas as pd
import numpy as np
# Load and inspect raw data
df = pd.read_csv("candidates.csv")
print(df.shape) # (1500, 8)
print(df.dtypes) # Check column types
print(df.isna().sum()) # Count missing values per column
# Clean in a reproducible chain
df_clean = (
df
.dropna(subset=["salary", "experience_years"]) # Drop rows missing critical fields
.assign(
salary=lambda x: x["salary"].clip(lower=20000, upper=500000), # Cap outliers
experience_years=lambda x: x["experience_years"].astype(int),
hired_date=lambda x: pd.to_datetime(x["hired_date"], errors="coerce"),
)
.drop_duplicates(subset=["email"]) # Remove duplicate candidates
.query("experience_years >= 0") # Filter invalid entries
.reset_index(drop=True)
)
print(f"Cleaned: {len(df)} -> {len(df_clean)} rows")Phương thức dropna(subset=...) loại bỏ các hàng thiếu giá trị ở những cột quan trọng, trong khi clip() giới hạn các giá trị ngoại lai trong khoảng hợp lý. Chuỗi method chaining (gọi phương thức nối tiếp) giúp mã nguồn dễ đọc và dễ bảo trì — mỗi bước biến đổi được thể hiện rõ ràng trên một dòng riêng. Tham số errors="coerce" trong pd.to_datetime() chuyển các giá trị ngày không hợp lệ thành NaT (Not a Time) thay vì gây lỗi, cho phép quy trình xử lý tiếp tục mà không bị gián đoạn.
Kể từ Pandas 2.2, chế độ Copy-on-Write (CoW) được bật mặc định. Điều này có nghĩa là các phép gán như df_clean["salary"] = ... sẽ tạo bản sao ngầm thay vì sửa đổi trực tiếp dữ liệu gốc. Hành vi này ngăn chặn lỗi SettingWithCopyWarning phổ biến và giúp mã nguồn an toàn hơn, nhưng người dùng cần lưu ý rằng một số mẫu gán cũ có thể hoạt động khác so với các phiên bản Pandas trước đó.
GroupBy, Aggregation và Feature Engineering
Sau khi dữ liệu đã được làm sạch, bước tiếp theo là tổng hợp thống kê và tạo các đặc trưng (feature) phù hợp cho mô hình Machine Learning. Phương thức groupby() của Pandas cho phép nhóm dữ liệu theo một hoặc nhiều cột và áp dụng các hàm tổng hợp — tương tự câu lệnh GROUP BY trong SQL nhưng linh hoạt hơn nhiều. Để hiểu sâu hơn về kỹ thuật tạo đặc trưng, có thể tham khảo bài tập chuyên sâu về Feature Engineering.
# pandas_groupby.py
import pandas as pd
# Aggregate candidate stats by department
dept_stats = (
df_clean
.groupby("department")
.agg(
avg_salary=("salary", "mean"),
median_experience=("experience_years", "median"),
headcount=("email", "count"),
max_salary=("salary", "max"),
)
.sort_values("avg_salary", ascending=False)
)
print(dept_stats.head())
# Create features for ML: encode categorical + add aggregated stats
df_features = (
df_clean
.assign(
# Ratio of individual salary to department average
salary_ratio=lambda x: x["salary"] / x.groupby("department")["salary"].transform("mean"),
# Time since hire in days
tenure_days=lambda x: (pd.Timestamp.now() - x["hired_date"]).dt.days,
# Binary encoding
is_senior=lambda x: (x["experience_years"] >= 5).astype(int),
)
)Phương thức agg() với cú pháp tên gọi (named aggregation) cho phép đặt tên rõ ràng cho từng cột kết quả, giúp mã nguồn tự giải thích. Hàm transform("mean") là một kỹ thuật quan trọng: thay vì trả về DataFrame đã gộp nhóm, nó phát lại (broadcast) giá trị trung bình của nhóm về từng hàng gốc — cho phép tính tỷ lệ lương cá nhân so với trung bình phòng ban mà không cần thao tác merge. Đặc trưng tenure_days và is_senior là ví dụ điển hình về Feature Engineering: chuyển đổi dữ liệu thô thành các biến có ý nghĩa thống kê mà mô hình có thể học được.
Sẵn sàng chinh phục phỏng vấn Data Science & ML?
Luyện tập với mô phỏng tương tác, flashcards và bài kiểm tra kỹ thuật.
Xây dựng Pipeline trong Scikit-Learn
Scikit-Learn Pipeline kết hợp các bước tiền xử lý và huấn luyện mô hình thành một đối tượng duy nhất, đảm bảo tính nhất quán giữa quá trình huấn luyện và dự đoán. ColumnTransformer cho phép áp dụng các phép biến đổi khác nhau cho từng nhóm cột — ví dụ, chuẩn hóa (scaling) cho cột số và mã hóa one-hot cho cột phân loại. Đây là nền tảng cho bất kỳ dự án phân loại có giám sát nào trong thực tế.
# sklearn_pipeline.py
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
import pandas as pd
# Define column groups
numeric_features = ["salary", "experience_years", "salary_ratio", "tenure_days"]
categorical_features = ["department", "role_level"]
target = "promoted"
# Split before any preprocessing
X = df_features[numeric_features + categorical_features]
y = df_features[target]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# Build the preprocessing + model pipeline
preprocessor = ColumnTransformer(
transformers=[
("num", StandardScaler(), numeric_features), # Scale numeric columns
("cat", OneHotEncoder(handle_unknown="ignore"), categorical_features), # Encode categories
]
)
pipeline = Pipeline([
("preprocessor", preprocessor),
("classifier", GradientBoostingClassifier(
n_estimators=200,
learning_rate=0.1,
max_depth=4,
random_state=42,
)),
])
# Train and evaluate
pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)
print(classification_report(y_test, y_pred))ColumnTransformer cho phép định nghĩa các bước tiền xử lý riêng biệt cho từng loại cột. StandardScaler chuẩn hóa các đặc trưng số về trung bình 0 và độ lệch chuẩn 1. OneHotEncoder(handle_unknown="ignore") chuyển các giá trị phân loại thành cột nhị phân và xử lý các danh mục chưa biết xuất hiện trong tập kiểm tra một cách an toàn. Mặc dù GradientBoostingClassifier vốn đã hoạt động tốt với dữ liệu chưa chuẩn hóa, việc tích hợp StandardScaler trong pipeline giúp dễ dàng thay thế mô hình bằng các thuật toán tuyến tính hoặc SVM khi cần thiết.
Cross-Validation và Hyperparameter Tuning
Một lần chia train-test duy nhất chỉ cung cấp ước lượng không ổn định về chất lượng mô hình. Cross-validation (kiểm chứng chéo) chia dữ liệu thành nhiều fold và tính trung bình kết quả — tạo ra đánh giá đáng tin cậy hơn về khả năng tổng quát hóa của mô hình. Sau đó, GridSearchCV tối ưu hóa các siêu tham số (hyperparameter) một cách có hệ thống thông qua cùng cơ chế cross-validation. Để tìm hiểu sâu hơn về các thuật toán Machine Learning, có thể tham khảo bài viết Giải thích các thuật toán Machine Learning.
# sklearn_tuning.py
from sklearn.model_selection import cross_val_score, GridSearchCV
import numpy as np
# 5-fold cross-validation on the full pipeline
scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring="f1")
print(f"F1 scores: {scores}")
print(f"Mean F1: {scores.mean():.3f} (+/- {scores.std() * 2:.3f})")
# Grid search over hyperparameters
param_grid = {
"classifier__n_estimators": [100, 200, 300],
"classifier__max_depth": [3, 4, 5],
"classifier__learning_rate": [0.05, 0.1, 0.2],
}
grid_search = GridSearchCV(
pipeline,
param_grid,
cv=5,
scoring="f1",
n_jobs=-1, # Use all CPU cores
verbose=1,
)
grid_search.fit(X_train, y_train)
print(f"Best params: {grid_search.best_params_}")
print(f"Best F1: {grid_search.best_score_:.3f}")
# Evaluate the best model on held-out test set
best_model = grid_search.best_estimator_
print(classification_report(y_test, best_model.predict(X_test)))Dấu gạch dưới kép trong "classifier__n_estimators" là quy ước của Scikit-Learn để truy cập tham số của các bước lồng nhau trong pipeline: classifier là tên bước trong pipeline, n_estimators là tham số của estimator bên trong. Tham số n_jobs=-1 sử dụng tất cả các lõi CPU có sẵn, giúp tăng tốc đáng kể quá trình tìm kiếm — với lưới 3x3x3 tổ hợp và 5-fold CV, tổng cộng 135 mô hình sẽ được huấn luyện.
Lỗi phổ biến nhất khi cross-validate với tiền xử lý: tính toán tham số chuẩn hóa trên toàn bộ tập huấn luyện trước khi chia fold. Điều này dẫn đến kết quả quá lạc quan vì dữ liệu validation gián tiếp ảnh hưởng đến quá trình chuẩn hóa. Scikit-Learn Pipeline giải quyết vấn đề này tự động: trong mỗi fold, toàn bộ bước tiền xử lý chỉ được fit trên training fold tương ứng, đảm bảo không có thông tin từ validation fold bị rò rỉ ngược.
Lưu và tải mô hình cho môi trường Production
Một mô hình đã huấn luyện chỉ thực sự có giá trị khi được lưu trữ (persist) và có thể tải lại trong các môi trường khác nhau — máy chủ web, quy trình xử lý batch, hoặc microservice. Scikit-Learn Pipeline có thể được tuần tự hóa (serialize) hoàn toàn: các tham số tiền xử lý (giá trị trung bình của Scaler, danh mục của Encoder) và trọng số mô hình đều được lưu trong một tệp duy nhất. Để có cái nhìn tổng quan về hệ sinh thái Data Science, có thể tham khảo các lộ trình học tập có sẵn trên nền tảng.
# sklearn_export.py
import joblib
from pathlib import Path
# Save the complete pipeline (preprocessor + model)
model_dir = Path("models")
model_dir.mkdir(exist_ok=True)
joblib.dump(best_model, model_dir / "promotion_model_v1.joblib")
# Load and predict in a different process
loaded_model = joblib.load(model_dir / "promotion_model_v1.joblib")
new_data = pd.DataFrame({
"salary": [75000],
"experience_years": [4],
"salary_ratio": [1.05],
"tenure_days": [730],
"department": ["Engineering"],
"role_level": ["Mid"],
})
prediction = loaded_model.predict(new_data)
probability = loaded_model.predict_proba(new_data)[:, 1]
print(f"Promoted: {bool(prediction[0])}, Confidence: {probability[0]:.2%}")Thư viện joblib được tối ưu hóa cho mảng số so với pickle và nhanh hơn đáng kể khi xử lý mô hình lớn. Điểm quan trọng: tệp .joblib chứa tất cả tham số Scaler và từ điển Encoder — khi tải trong tiến trình khác, không cần xử lý lại dữ liệu huấn luyện. Phương thức predict_proba() trả về xác suất cho từng lớp; biểu thức [:, 1] trích xuất xác suất của lớp dương (được thăng chức), vốn hữu ích hơn trong thực tế so với chỉ dự đoán nhị phân đơn thuần.
Kết luận
NumPy, Pandas và Scikit-Learn bổ trợ cho nhau một cách liền mạch trong quy trình Data Science:
- NumPy cung cấp nền tảng toán học ma trận và các phép toán mảng hiệu năng cao, là cơ sở cho toàn bộ hệ sinh thái khoa học Python.
- Pandas xây dựng trên NumPy, bổ sung khả năng thao tác dữ liệu linh hoạt với cột có tên và chỉ mục, lý tưởng cho dữ liệu dạng bảng thực tế.
- Scikit-Learn sử dụng cả hai làm định dạng đầu vào cho các thuật toán của mình, cung cấp Pipeline nhất quán từ tiền xử lý đến triển khai mô hình.
- Quy trình được trình bày trong bài viết — tải và làm sạch dữ liệu, tạo đặc trưng, xây dựng pipeline, cross-validate và lưu mô hình — không phải là lý thuyết hàn lâm mà là tiêu chuẩn thực tế trong các đội ngũ Data Science chuyên nghiệp.
- Nắm vững ba thư viện này mở ra cánh cửa tới các framework phức tạp hơn như PyTorch hoặc XGBoost — vì các quy ước API của chúng đều dựa trên cùng các nguyên tắc cơ bản.
Những ai muốn tìm hiểu sâu hơn về các thuật toán nền tảng có thể thực hành với các bài tập chuyên sâu về Feature Engineering và phân loại có giám sát trên SharpSkill.
Bắt đầu luyện tập!
Kiểm tra kiến thức với mô phỏng phỏng vấn và bài kiểm tra kỹ thuật.
Thẻ
Chia sẻ
Bài viết liên quan

Thuật Toán Học Máy: Hướng Dẫn Toàn Diện Cho Phỏng Vấn Kỹ Thuật 2026
Nắm vững các thuật toán học máy cốt lõi được kiểm tra trong phỏng vấn kỹ thuật năm 2026. Bao gồm học có giám sát, học không giám sát, phương pháp ensemble, chỉ số đánh giá và chính quy hóa với các triển khai Python thực tế.

25 Câu hỏi Phỏng vấn Data Science Hàng đầu năm 2026
Các câu hỏi phỏng vấn data science về thống kê, machine learning, feature engineering, deep learning và thiết kế hệ thống — kèm code Python và đáp án chuyên gia.