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.

25 Câu hỏi Phỏng vấn Data Science Hàng đầu năm 2026

Năm 2026, vai trò Data Scientist tiếp tục nằm trong top những vị trí được săn đón nhiều nhất trên thị trường công nghệ toàn cầu. Các buổi phỏng vấn ngày càng đòi hỏi chiều sâu kỹ thuật cao hơn: từ nền tảng xác suất, thuật toán học máy đến thiết kế hệ thống và triển khai mô hình ở quy mô lớn. Bài viết này tổng hợp 25 câu hỏi phỏng vấn Data Science phổ biến nhất năm 2026, kèm đáp án chi tiết và code Python minh họa thực tế.

Nhà tuyển dụng đánh giá điều gì?

Trong các buổi phỏng vấn Data Science cấp trung và cao cấp, nhà tuyển dụng không chỉ kiểm tra kiến thức lý thuyết mà còn đánh giá khả năng tư duy phân tích có cấu trúc, hiểu biết về sự đánh đổi giữa các phương pháp, và kỹ năng diễn đạt kết quả kỹ thuật cho đối tượng phi kỹ thuật. Việc nắm vững cả lý thuyết lẫn ứng dụng thực tế sẽ tạo ra sự khác biệt rõ rệt.

Xác suất và Nền tảng Thống kê

Câu 1: Tung đồng xu 10 lần, 8 lần ra mặt ngửa. Đồng xu có bị lệch không?

Đây là câu hỏi kinh điển để kiểm tra hiểu biết về kiểm định giả thuyết. Giả thuyết null H₀ cho rằng đồng xu công bằng với xác suất p = 0,5. Giả thuyết đối H₁ là p ≠ 0,5 (kiểm định hai phía).

Phân phối số lần ra mặt ngửa tuân theo phân phối nhị thức Binomial(n=10, p=0,5). Với 8 lần ra mặt ngửa trong 10 lần tung, p-value hai phía xấp xỉ 0,109. Với mức ý nghĩa α = 0,05, không có đủ bằng chứng để bác bỏ H₀.

Điều quan trọng cần nhấn mạnh trong phỏng vấn: Lỗi loại I (Type I Error) xảy ra khi bác bỏ H₀ khi H₀ đúng (xác suất = α). Lỗi loại II (Type II Error) xảy ra khi không bác bỏ H₀ khi H₀ sai (xác suất = β). Với cỡ mẫu n=10, kiểm định có độ mạnh thống kê (statistical power) thấp — đây là lý do cần thu thập thêm dữ liệu trước khi đưa ra kết luận.

python
# binomial_test.py
from scipy import stats

# Two-sided binomial test: is the coin fair?
result = stats.binomtest(k=8, n=10, p=0.5, alternative='two-sided')
print(f"p-value: {result.pvalue:.4f}")  # 0.1094 (two-sided)
print(f"Reject H0 at alpha=0.05? {result.pvalue < 0.05}")  # False

Câu 2: Sự khác biệt giữa suy luận Bayesian và Frequentist là gì?

Hai trường phái thống kê này có triết lý căn bản khác nhau về ý nghĩa của xác suất.

Frequentist: Xác suất là tần suất xuất hiện trong vô số thí nghiệm lặp lại. Tham số là cố định nhưng chưa biết. Khoảng tin cậy 95% (Confidence Interval) có nghĩa là: nếu lặp lại thí nghiệm vô số lần, 95% các khoảng được tạo ra sẽ chứa tham số thực. Khoảng này không nói lên xác suất tham số nằm trong đó.

Bayesian: Xác suất thể hiện mức độ tin tưởng chủ quan. Tham số được xem như biến ngẫu nhiên có phân phối. Bắt đầu từ prior belief, cập nhật bằng dữ liệu để thu được phân phối posterior. Khoảng tin cậy Bayesian (Credible Interval) có thể phát biểu trực tiếp: "Xác suất tham số nằm trong khoảng này là 95%."

Frequentist phù hợp khi cần kiểm định giả thuyết khách quan, kiểm soát tỷ lệ lỗi (clinical trials, A/B testing với tiêu chuẩn nghiêm ngặt). Bayesian phù hợp khi có prior knowledge đáng tin cậy, cần cập nhật liên tục (fraud detection, recommendation systems), hoặc khi cỡ mẫu nhỏ.

python
# bayesian_vs_frequentist.py
import numpy as np
from scipy import stats

# Frequentist: confidence interval for a mean
data = np.array([23.1, 25.4, 22.8, 24.9, 23.7, 25.1, 24.3])
ci = stats.t.interval(0.95, df=len(data)-1, loc=np.mean(data), scale=stats.sem(data))
print(f"95% CI (frequentist): [{ci[0]:.2f}, {ci[1]:.2f}]")

# Bayesian: posterior with conjugate prior (Normal-Normal)
prior_mean, prior_var = 24.0, 4.0  # prior belief
data_mean, data_var = np.mean(data), np.var(data, ddof=1) / len(data)
# Posterior parameters (conjugate update)
post_var = 1 / (1/prior_var + 1/data_var)
post_mean = post_var * (prior_mean/prior_var + data_mean/data_var)
post_ci = stats.norm.interval(0.95, loc=post_mean, scale=np.sqrt(post_var))
print(f"95% credible interval (Bayesian): [{post_ci[0]:.2f}, {post_ci[1]:.2f}]")

Câu 3: Khi nào Định lý Giới hạn Trung tâm (CLT) thất bại?

Định lý Giới hạn Trung tâm phát biểu rằng tổng của n biến ngẫu nhiên độc lập, cùng phân phối sẽ hội tụ về phân phối chuẩn khi n → ∞. Tuy nhiên, CLT có những điều kiện tiên quyết quan trọng có thể bị vi phạm trong thực tế.

Điều kiện phương sai hữu hạn: CLT yêu cầu phương sai của phân phối gốc phải hữu hạn. Các phân phối heavy-tailed như Cauchy, Pareto với tail index α ≤ 2, hoặc log-normal với tham số lớn không thỏa mãn điều kiện này. Phân phối Cauchy, ví dụ, không có kỳ vọng hay phương sai xác định — CLT hoàn toàn không áp dụng được.

Phụ thuộc giữa các quan sát: CLT chuẩn giả định các biến độc lập. Chuỗi thời gian có autocorrelation cao, dữ liệu có cấu trúc cluster, hoặc dữ liệu không gian có spatial correlation đều vi phạm giả định này. Cần sử dụng các phiên bản mở rộng của CLT (mixing conditions) hoặc bootstrap.

Cỡ mẫu không đủ lớn: "n đủ lớn" phụ thuộc vào mức độ skewness của phân phối gốc. Quy tắc ngón tay n ≥ 30 chỉ đúng với phân phối gần chuẩn. Phân phối có skewness cao (ví dụ: income distribution) cần n lớn hơn nhiều.

Khi CLT thất bại, các phương án thay thế gồm: Stable distributions (Lévy-stable), bootstrap với cỡ mẫu lớn, hoặc các phương pháp nonparametric.

Feature Engineering và Chuẩn bị Dữ liệu

Câu 4: Tác động của giá trị thiếu và các chiến lược xử lý ngoài imputation đơn giản là gì?

Dữ liệu thiếu không phải lúc nào cũng ngẫu nhiên — cơ chế thiếu dữ liệu ảnh hưởng trực tiếp đến chiến lược xử lý.

MCAR (Missing Completely At Random): Xác suất thiếu không phụ thuộc vào bất kỳ biến nào, kể cả giá trị thiếu. Trường hợp lý tưởng nhất — có thể xóa hàng mà không gây bias.

MAR (Missing At Random): Xác suất thiếu phụ thuộc vào các biến quan sát được nhưng không phụ thuộc vào giá trị thiếu chính nó. Multiple imputation, KNN imputation hoạt động tốt.

MNAR (Missing Not At Random): Xác suất thiếu phụ thuộc vào giá trị thiếu. Ví dụ: người thu nhập cao có xu hướng không khai báo thu nhập. Đây là trường hợp khó nhất — cần mô hình hóa cơ chế thiếu.

Các chiến lược nâng cao: KNN Imputation bảo toàn cấu trúc cục bộ của dữ liệu bằng cách sử dụng k hàng xóm gần nhất. Iterative Imputation (MICE) mô hình hóa mỗi feature bằng các feature còn lại, lặp đi lặp lại cho đến khi hội tụ. Missingness Indicator: Thêm cột nhị phân cho biết giá trị có bị thiếu không — bản thân pattern thiếu có thể là tín hiệu quan trọng (ví dụ: người không trả lời câu hỏi thu nhập).

python
# missing_data_strategies.py
import pandas as pd
from sklearn.impute import KNNImputer, SimpleImputer
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer

df = pd.DataFrame({
    'age': [25, 30, None, 45, None, 38],
    'income': [50000, None, 70000, 90000, 60000, None],
    'score': [85, 90, 78, None, 88, 92]
})

# Strategy 1: KNN imputation (preserves local structure)
knn_imp = KNNImputer(n_neighbors=2)
df_knn = pd.DataFrame(knn_imp.fit_transform(df), columns=df.columns)

# Strategy 2: Iterative imputation (MICE-like, models each feature)
iter_imp = IterativeImputer(max_iter=10, random_state=42)
df_iter = pd.DataFrame(iter_imp.fit_transform(df), columns=df.columns)

# Strategy 3: Add missingness indicator (preserves signal in the pattern)
df['income_missing'] = df['income'].isna().astype(int)
print(df_knn.round(1))

Câu 5: Target encoding so với one-hot encoding — khi nào nên dùng cái nào?

One-hot encoding phù hợp với categorical features có cardinality thấp (dưới 10-15 giá trị). Nó không giả định thứ tự hay khoảng cách giữa các category, nhưng tạo ra vấn đề "curse of dimensionality" khi cardinality cao.

Target encoding thay thế mỗi category bằng mean của target variable trong category đó. Hiệu quả với high-cardinality features (tên thành phố, mã sản phẩm, ID người dùng) vì chỉ thêm một cột duy nhất. Tuy nhiên, nếu làm không đúng, target encoding gây ra data leakage nghiêm trọng: model học được thông tin từ target variable trong tập train theo cách trực tiếp.

Giải pháp: K-fold regularization — tính mean target chỉ từ các fold training, không bao giờ sử dụng dữ liệu của chính quan sát đó để encode nó. Ngoài ra có thể áp dụng smoothing: blend category mean với global mean theo công thức có weight dựa trên số lượng quan sát trong category.

python
# target_encoding.py
import pandas as pd
import numpy as np
from sklearn.model_selection import KFold

def target_encode_kfold(df, col, target, n_splits=5):
    """Target encoding with K-fold regularization to prevent leakage."""
    encoded = pd.Series(index=df.index, dtype=float)
    global_mean = df[target].mean()
    kf = KFold(n_splits=n_splits, shuffle=True, random_state=42)

    for train_idx, val_idx in kf.split(df):
        # Compute means only from training fold
        means = df.iloc[train_idx].groupby(col)[target].mean()
        encoded.iloc[val_idx] = df.iloc[val_idx][col].map(means)

    # Fill categories unseen in training fold with global mean
    encoded.fillna(global_mean, inplace=True)
    return encoded

df = pd.DataFrame({
    'city': ['Paris', 'Lyon', 'Paris', 'Marseille', 'Lyon', 'Paris',
             'Marseille', 'Lyon', 'Paris', 'Marseille'],
    'hired': [1, 0, 1, 0, 1, 1, 0, 0, 1, 1]
})
df['city_encoded'] = target_encode_kfold(df, 'city', 'hired')
print(df[['city', 'city_encoded', 'hired']])

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.

Các Khái niệm Cốt lõi Machine Learning

Câu 6: Đánh đổi Bias-Variance trong các mô hình cây quyết định là gì?

Bias-variance tradeoff là một trong những khái niệm nền tảng nhất của học máy. Tổng lỗi dự đoán có thể phân tích thành: Lỗi = Bias² + Variance + Irreducible Noise.

Cây quyết định đơn (Single Decision Tree): Độ sâu không hạn chế dẫn đến bias thấp (mô hình có thể fit mọi pattern), nhưng variance rất cao (cực kỳ nhạy với thay đổi nhỏ trong training data). Đây là ví dụ điển hình của overfitting.

Random Forest: Kết hợp nhiều cây quyết định thông qua bagging (bootstrap aggregating) và random feature subsampling. Giảm variance đáng kể bằng cách trung bình hóa nhiều cây độc lập, nhưng bias tăng nhẹ so với cây đơn đầy đủ. Hoạt động tốt với các feature có tầm quan trọng tương đương nhau.

Gradient Boosting (XGBoost, LightGBM): Xây dựng cây theo thứ tự, mỗi cây học phần dư (residuals) của cây trước. Sử dụng cây nông (depth 3-6) để kiểm soát variance, tích lũy nhiều cây để giảm bias. Learning rate nhỏ + nhiều cây thường hiệu quả hơn learning rate lớn + ít cây. Nhạy cảm hơn với hyperparameter tuning so với Random Forest.

Câu 7: Tại sao Accuracy thất bại với dữ liệu mất cân bằng?

Với dataset có tỷ lệ 95:5 giữa lớp âm và lớp dương, một mô hình luôn dự đoán "âm" sẽ đạt accuracy 95% nhưng hoàn toàn vô dụng. Đây là lý do các metric chuyên biệt cần thiết.

Precision: Trong tất cả những gì mô hình dự đoán là dương, bao nhiêu phần trăm thực sự là dương? Quan trọng khi false positive có chi phí cao (spam filter, fraud detection).

Recall (Sensitivity): Trong tất cả các trường hợp dương thực sự, mô hình phát hiện được bao nhiêu? Quan trọng khi false negative có chi phí cao (bệnh hiểm nghèo, phát hiện gian lận tài chính).

F1 Score: Harmonic mean của Precision và Recall. F1 = 2×(P×R)/(P+R). Cân bằng cả hai.

AUPRC (Area Under Precision-Recall Curve): Tổng hợp hiệu suất trên mọi ngưỡng phân loại, đặc biệt nhạy với hiệu suất trên lớp thiểu số. Được ưa dùng hơn ROC AUC khi imbalance nghiêm trọng.

ROC AUC: Xác suất mô hình xếp hạng một ví dụ dương cao hơn một ví dụ âm ngẫu nhiên. Ổn định với imbalance ở mức vừa phải, nhưng có thể lạc quan quá mức khi imbalance cực đoan.

python
# imbalanced_metrics.py
from sklearn.metrics import (
    classification_report, precision_recall_curve,
    average_precision_score, roc_auc_score
)
import numpy as np

# Simulated predictions on imbalanced data
np.random.seed(42)
y_true = np.array([0]*950 + [1]*50)  # 95/5 imbalance
y_scores = np.random.beta(2, 5, 1000)  # predicted probabilities
y_scores[y_true == 1] += 0.3  # positive class scores slightly higher
y_scores = np.clip(y_scores, 0, 1)
y_pred = (y_scores > 0.5).astype(int)

print(classification_report(y_true, y_pred, digits=3))
print(f"ROC AUC: {roc_auc_score(y_true, y_scores):.3f}")
print(f"Average Precision (AUPRC): {average_precision_score(y_true, y_scores):.3f}")

Câu 8: L1 so với L2 Regularization — sự khác biệt cốt lõi là gì?

Cả hai đều thêm penalty vào hàm mất mát để ngăn overfitting, nhưng có tính chất toán học khác nhau quan trọng.

L1 (Lasso): Penalty = λ×Σ|wᵢ|. Gradient của |w| không liên tục tại w=0, điều này khiến Lasso có xu hướng đưa các hệ số nhỏ về đúng 0 — tạo ra sparse solutions. Lý tưởng cho feature selection khi nghi ngờ chỉ một tập nhỏ features thực sự quan trọng.

L2 (Ridge): Penalty = λ×Σwᵢ². Gradient smooth, co tất cả hệ số về gần 0 nhưng không bao giờ chính xác bằng 0 (shrinkage). Tốt hơn khi nhiều features đều đóng góp vào dự đoán.

Elastic Net: Kết hợp cả L1 và L2 với hai hyperparameter α (mix ratio) và λ (strength). Phù hợp khi có nhiều features tương quan cao với nhau (L1 chỉ chọn một trong số chúng, trong khi Elastic Net có thể giữ cả nhóm).

Từ góc độ Bayesian: L2 tương đương với Gaussian prior trên weights; L1 tương đương với Laplace prior (nhọn hơn ở gốc tọa độ, dẫn đến sparsity).

Câu 9: XGBoost và LightGBM xử lý categorical features khác nhau như thế nào?

Đây là câu hỏi thực tế quan trọng thường bị bỏ qua trong sách giáo khoa.

XGBoost (phiên bản chuẩn): Không hỗ trợ categorical features native. Người dùng phải tự encode trước (one-hot, label encoding, target encoding). Từ phiên bản 1.6 trở đi có thêm tùy chọn enable_categorical=True với partition-based splits, nhưng vẫn còn hạn chế.

LightGBM: Hỗ trợ categorical features native thông qua optimal split finding — thuật toán tìm phân hoạch tối ưu của các category thay vì xử lý theo thứ tự ordinal. Thiết lập categorical_feature trong parameters. Với high-cardinality features, LightGBM nhanh hơn và thường cho kết quả tốt hơn so với one-hot encoding + XGBoost.

Lưu ý thực tế: Dù LightGBM có hỗ trợ native categorical, target encoding với K-fold regularization vẫn thường cho kết quả tốt hơn với ultra-high-cardinality features (hàng nghìn category trở lên).

Đánh giá và Xác thực Mô hình

Câu 10: Data Leakage — 3 nguồn phổ biến nhất là gì?

Data leakage là một trong những nguyên nhân hàng đầu khiến model hoạt động tốt trên validation nhưng thất bại trong production. Có 3 dạng chính:

1. Temporal Leakage (Rò rỉ thời gian): Sử dụng thông tin từ tương lai để dự đoán quá khứ. Ví dụ: dự đoán liệu khách hàng có rời bỏ không, nhưng dùng số lần gọi hỗ trợ trong 7 ngày sau ngày dự đoán như một feature.

2. Target Leakage (Rò rỉ mục tiêu): Feature chứa thông tin trực tiếp về target. Ví dụ: dùng "đã kê đơn thuốc" để dự đoán "bệnh nhân có bị bệnh X không". Hoặc target encoding tính toán trên toàn bộ tập data (kể cả test set).

3. Preprocessing Leakage (Rò rỉ tiền xử lý): Fit scaler, imputer, hay feature selector trên toàn bộ data trước khi cross-validation. Điều này làm test fold "biết" thông tin từ training fold, dẫn đến ước tính performance quá lạc quan.

Phòng ngừa: Luôn sử dụng Pipeline của scikit-learn để đảm bảo mọi preprocessing step chỉ được fit trên training fold và transform test fold.

python
# leakage_prevention.py
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
import numpy as np

X = np.random.randn(1000, 10)
y = (X[:, 0] + X[:, 1] > 0).astype(int)

# WRONG: fit scaler on all data, then cross-validate
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)  # leakage: test fold info in scaling

# CORRECT: pipeline ensures preprocessing fits only on training folds
pipeline = Pipeline([
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler()),
    ('model', GradientBoostingClassifier(n_estimators=100, random_state=42))
])
scores = cross_val_score(pipeline, X, y, cv=5, scoring='roc_auc')
print(f"AUC (no leakage): {scores.mean():.3f} +/- {scores.std():.3f}")

Câu 11: Khi nào dùng Time-Series Cross-Validation thay vì K-Fold thông thường?

Với dữ liệu có thứ tự thời gian, K-fold chuẩn vi phạm giả định của thực tế: mô hình sẽ được "huấn luyện" trên dữ liệu tương lai để dự đoán quá khứ.

TimeSeriesSplit của scikit-learn giải quyết vấn đề này bằng cách chỉ sử dụng dữ liệu quá khứ làm training set và dữ liệu tương lai làm validation set trong mỗi fold. Mỗi fold, training window mở rộng ra.

Các biến thể khác: Expanding window (training set ngày càng lớn hơn), Rolling window (training set có kích thước cố định), và Purged K-Fold (thêm gap giữa training và validation để loại bỏ leakage từ autocorrelation).

Bẫy K-Fold với dữ liệu chuỗi thời gian

Sử dụng K-fold chuẩn (shuffle=True) với dữ liệu chuỗi thời gian là một sai lầm nghiêm trọng thường gặp ngay cả ở data scientist có kinh nghiệm. Model sẽ đạt kết quả validation tốt giả tạo vì nó đã "nhìn" dữ liệu tương lai trong quá trình training. Luôn dùng TimeSeriesSplit hoặc tương đương khi thứ tự thời gian có ý nghĩa.

Deep Learning và Mạng Neural

Câu 12: ReLU so với Sigmoid — vấn đề Dying ReLU là gì?

SigmoidTanh là các hàm kích hoạt truyền thống, nhưng chúng gây ra vấn đề vanishing gradients: với đầu vào lớn (dương hoặc âm), gradient tiến về 0, làm các layer đầu trong mạng sâu học cực kỳ chậm hoặc không học được.

ReLU (Rectified Linear Unit): f(x) = max(0, x). Đơn giản, gradient không vanish với x > 0, tính toán nhanh. Tuy nhiên, có vấn đề Dying ReLU: nếu một neuron liên tục nhận đầu vào âm (ví dụ do learning rate quá lớn hoặc khởi tạo weights không tốt), gradient sẽ luôn bằng 0 và neuron đó không bao giờ cập nhật nữa — nó "chết".

Leaky ReLU: f(x) = max(0.01x, x). Cho phép gradient nhỏ với x < 0, giải quyết dying ReLU.

GELU (Gaussian Error Linear Unit): f(x) = x × Φ(x). Được sử dụng trong BERT, GPT và hầu hết các Transformer hiện đại. Smooth và thực nghiệm cho kết quả tốt hơn ReLU cho NLP. ELUSwish cũng là các lựa chọn phổ biến.

Câu 13: Cơ chế Attention và Transformer hoạt động như thế nào?

Attention mechanism là bước đột phá cho phép model học được mối quan hệ giữa các vị trí trong sequence mà không phụ thuộc vào khoảng cách.

Self-Attention: Mỗi token tạo ra ba vector từ embedding của nó: Query (Q), Key (K), Value (V) thông qua các ma trận tuyến tính học được. Attention score giữa token i và token j là softmax(QᵢKⱼᵀ/√d_k). Output là weighted sum của các Value vectors.

Ưu điểm so với RNN: RNN xử lý sequence tuần tự, không thể song song hóa. Transformer xử lý toàn bộ sequence song song, với độ phức tạp O(n²) cho attention (n là độ dài sequence) nhưng O(1) về mặt depth — tất cả vị trí kết nối trực tiếp. Điều này làm Transformer scale tốt hơn nhiều với GPU/TPU hiện đại.

Multi-head Attention: Chạy nhiều attention heads song song với các projection khác nhau, cho phép model chú ý đến nhiều loại quan hệ cùng lúc (syntax, semantics, coreference...).

python
# self_attention.py
import torch
import torch.nn.functional as F

def self_attention(x, d_k):
    """Scaled dot-product self-attention from scratch."""
    # x shape: (batch_size, seq_len, d_model)
    batch_size, seq_len, d_model = x.shape

    # Linear projections for Q, K, V
    W_q = torch.randn(d_model, d_k) * 0.1
    W_k = torch.randn(d_model, d_k) * 0.1
    W_v = torch.randn(d_model, d_k) * 0.1

    Q = x @ W_q  # (batch, seq_len, d_k)
    K = x @ W_k
    V = x @ W_v

    # Scaled dot-product attention
    scores = Q @ K.transpose(-2, -1) / (d_k ** 0.5)  # (batch, seq_len, seq_len)
    weights = F.softmax(scores, dim=-1)  # attention weights
    output = weights @ V  # (batch, seq_len, d_k)

    return output, weights

# Example: 1 batch, 4 tokens, 8-dim embeddings
x = torch.randn(1, 4, 8)
out, attn = self_attention(x, d_k=8)
print(f"Output shape: {out.shape}")    # (1, 4, 8)
print(f"Attention weights:\n{attn[0].detach().numpy().round(3)}")

Câu 14: Fine-tuning so với Transfer Learning — khi nào áp dụng cái nào?

Đây là câu hỏi thực tế quan trọng khi làm việc với các pretrained models lớn.

Feature Extraction (Transfer Learning thuần túy): Đóng băng tất cả weights của pretrained model, chỉ thêm và train một vài layer cuối. Phù hợp khi: dataset mục tiêu nhỏ (vài trăm đến vài nghìn samples), task tương tự với pretrained task, muốn tránh overfitting.

Fine-tuning: Unfreeze một số hoặc tất cả layers của pretrained model và train với learning rate nhỏ hơn nhiều. Phù hợp khi: có dataset đủ lớn (hàng chục nghìn samples trở lên), domain có sự khác biệt đáng kể so với pretraining data (ví dụ: medical imaging vs ImageNet), cần hiệu suất tối đa.

Thực hành tốt nhất: Sử dụng differential learning rates — layer đầu (học các features cơ bản như edge, texture) dùng learning rate rất nhỏ hoặc đóng băng; layer cuối (task-specific) dùng learning rate lớn hơn. Gradual unfreezing — mở dần từng layer từ trên xuống.

SQL và Thao tác Dữ liệu

Câu 15: Tìm mức lương cao thứ hai mỗi phòng ban mà không dùng window functions

Đây là câu hỏi SQL kinh điển thường gặp trong các buổi phỏng vấn Data Science. Correlated subquery là phương pháp không dùng window functions:

sql
-- second_highest_salary.sql
-- Approach: correlated subquery counting distinct higher salaries
SELECT d.department_name, e.employee_name, e.salary
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE (
    SELECT COUNT(DISTINCT e2.salary)
    FROM employees e2
    WHERE e2.department_id = e.department_id
      AND e2.salary > e.salary
) = 1
ORDER BY d.department_name;

Logic: với mỗi nhân viên e, đếm số mức lương KHÁC NHAU cao hơn lương của họ trong cùng phòng ban. Nếu con số đó bằng 1, thì họ có đúng 1 mức lương cao hơn — tức là họ đứng thứ 2.

Trong phỏng vấn, nhà tuyển dụng thường hỏi tiếp: "Bây giờ hãy viết lại bằng window functions." Đáp án sẽ dùng DENSE_RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) và lọc WHERE rnk = 2.

Câu 16: Sự khác biệt giữa WHERE và HAVING trong SQL là gì?

Đây là câu hỏi về thứ tự thực thi SQL, thường gây nhầm lẫn.

WHERE lọc các hàng trước khi GROUP BY được thực thi. Nó hoạt động trực tiếp trên dữ liệu raw. Không thể dùng aggregate functions (SUM, COUNT, AVG) trong WHERE.

HAVING lọc các nhóm sau khi GROUP BY và aggregation đã xong. Chỉ có ý nghĩa khi dùng với GROUP BY. Có thể sử dụng aggregate functions.

Thứ tự thực thi SQL: FROM → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.

Sai lầm phổ biến: viết WHERE COUNT(*) > 5 thay vì HAVING COUNT(*) > 5. Lỗi khác: dùng alias từ SELECT trong WHERE hay HAVING (SELECT thực thi sau, nên alias chưa tồn tại ở bước WHERE/HAVING — trừ một số database như PostgreSQL có hỗ trợ).

Data Science Ứng dụng và Thiết kế Hệ thống

Câu 17: Thiết kế A/B test cho thuật toán recommendation mới

Thiết kế A/B test nghiêm ngặt yêu cầu 5 thành phần:

1. Metric: Xác định rõ primary metric (ví dụ: CTR, revenue per user, 7-day retention) và guardrail metrics (latency, error rate, revenue của segment khác). Tránh HiPPO-driven metric selection.

2. Power Analysis: Tính cỡ mẫu cần thiết dựa trên: effect size tối thiểu có ý nghĩa kinh doanh (MDE), significance level α (thường 0.05), power 1-β (thường 0.8), phương sai của metric từ dữ liệu lịch sử. Không bao giờ "peek" liên tục vào kết quả và dừng sớm khi thấy p < 0.05 (optional stopping = lỗi thống kê nghiêm trọng).

3. Randomization Unit: Thường là user-level (đảm bảo cùng user luôn thấy cùng variant). Với một số platform, có thể cần session-level hay cookie-level.

4. Guardrail Metrics: Đặt ngưỡng tự động dừng experiment nếu một metric quan trọng (latency, error rate, revenue) giảm quá ngưỡng cho phép.

5. Pre-registration: Định nghĩa metric, hypothesis, và decision criteria TRƯỚC khi chạy test để tránh p-hacking.

Tính cỡ mẫu cho A/B test

Cỡ mẫu cần thiết cho mỗi nhóm có thể ước tính bằng công thức: n ≈ 2(z_α/2 + z_β)² × σ² / δ², trong đó σ² là phương sai metric và δ là minimum detectable effect. Với metric nhị phân (CTR), σ² = p(1-p). Luôn nhân kết quả với 1.1-1.2 để dự phòng data loss và exclusions. Sử dụng statsmodels.stats.power trong Python để tính chính xác.

Câu 18: Model hoạt động tốt trên validation nhưng thất bại trong production — nguyên nhân là gì?

Đây là tình huống xảy ra thường xuyên trong thực tế và thường do một trong các nguyên nhân sau:

Distribution Shift (Covariate Shift): Phân phối của features trong production khác với training data. Ví dụ: model train trên dữ liệu mùa hè, deploy vào mùa đông; hoặc hành vi người dùng thay đổi sau khi có sự kiện lớn.

Feature Skew (Đặc trưng không đồng nhất): Cách features được tính toán trong training pipeline khác với serving pipeline. Ví dụ: training dùng batch aggregation (7-day moving average tính trên full history), nhưng serving chỉ có real-time data.

Label Leakage Chỉ Có Trong Training: Một số features chỉ available sau khi label được tạo ra trong training, nhưng không có trong production (ví dụ: timestamps của sự kiện tương lai).

Giải pháp: monitoring distribution shift (PSI, KS test), feature store để đảm bảo feature consistency, shadow mode deployment (chạy model mới song song với model cũ để so sánh), và comprehensive logging của inputs/outputs.

Câu 19: CAP Theorem và Feature Stores trong hệ thống ML

CAP Theorem phát biểu rằng một distributed system không thể đồng thời đảm bảo cả ba: Consistency (tất cả nodes thấy cùng data), Availability (mọi request đều nhận được response), và Partition Tolerance (hệ thống tiếp tục hoạt động dù có network partition). Phải chọn 2 trong 3.

Trong bối cảnh Feature Stores: serving features cần latency thấp (Availability) và có thể chấp nhận eventual consistency (đặc biệt với behavioral features). Vì vậy, feature stores thường dùng kiến trúc dual-store:

  • Online store (Redis, DynamoDB): Low-latency serving, availability-first, eventual consistency. Lưu feature values đã được precomputed.
  • Offline store (S3, BigQuery, Hive): Batch computation, consistency-first, dùng để train và backfill.

Feature pipeline viết vào cả hai store. Consistency được đảm bảo bởi shared feature definitions (Feature Registry) và point-in-time correct joins để tránh leakage khi tạo training data.

Câu 20: Concept Drift trong production — phát hiện và xử lý như thế nào?

Concept Drift xảy ra khi mối quan hệ giữa features và target thay đổi theo thời gian. Khác với covariate shift (phân phối features thay đổi), concept drift ảnh hưởng trực tiếp đến decision boundary.

Phát hiện:

  • PSI (Population Stability Index): So sánh phân phối của một biến giữa hai thời điểm. PSI < 0.1 (ổn định), 0.1-0.25 (cần theo dõi), > 0.25 (drift đáng kể).
  • Statistical Tests: Kolmogorov-Smirnov test, chi-squared test cho biến phân loại, ADWIN (Adaptive Windowing) cho streaming data.
  • Model Performance Monitoring: Theo dõi AUC, F1, hoặc business metrics theo thời gian. Drift thường thể hiện qua performance suy giảm.

Xử lý:

  • Periodic Retraining: Train lại model theo lịch (hàng tuần/tháng) với data mới nhất.
  • Online Learning: Cập nhật model incrementally với từng batch data mới (phù hợp với linear models, decision trees với Hoeffding bounds).
  • Ensemble với Model Mới: Dần dần tăng weight của model mới, giảm weight của model cũ.

Python và Pandas

Câu 21: Sự khác biệt giữa apply(), map() và transform() trong Pandas

Đây là câu hỏi thực tế quan trọng thường gặp trong vòng coding interview.

map(): Áp dụng trên Series, element-wise. Thường dùng để map values từ dictionary hay áp dụng hàm đơn giản. Không dùng được trực tiếp trên DataFrame.

apply(): Áp dụng trên Series (element-wise) hoặc DataFrame (theo rows hay columns). Linh hoạt nhất nhưng chậm nhất — nên dùng vectorized operations khi có thể.

transform(): Luôn trả về output có cùng shape với input. Thường dùng với groupby() để tính group statistics và broadcast lại vào DataFrame gốc — rất hữu ích khi muốn thêm cột như "mean của group" hay "normalized score trong group".

python
# pandas_operations.py
import pandas as pd

df = pd.DataFrame({
    'team': ['A', 'A', 'B', 'B', 'A'],
    'score': [10, 20, 30, 40, 50]
})

# map: element-wise on Series
df['team_upper'] = df['team'].map({'A': 'Alpha', 'B': 'Beta'})

# apply: arbitrary function per row
df['score_label'] = df['score'].apply(lambda x: 'high' if x > 25 else 'low')

# transform: group-level, same shape output (broadcasts back)
df['team_mean'] = df.groupby('team')['score'].transform('mean')
df['score_normalized'] = df.groupby('team')['score'].transform(
    lambda x: (x - x.mean()) / x.std()
)
print(df)

Câu 22: GIL của Python và tác động đến Data Science là gì?

GIL (Global Interpreter Lock) là cơ chế trong CPython ngăn nhiều threads chạy Python bytecode đồng thời trong cùng một process. Chỉ một thread Python có thể thực thi tại một thời điểm.

Tác động với Data Science:

CPU-bound tasks (matrix computation, model training thuần Python): Threading không cải thiện hiệu suất vì GIL ngăn parallelism thực sự. Phải dùng multiprocessing (mỗi process có GIL riêng) hoặc các thư viện như NumPy/Pandas/scikit-learn release GIL khi gọi C extensions.

I/O-bound tasks (đọc file, database queries, API calls): GIL được release trong khi chờ I/O, nên threading hoạt động hiệu quả. Asyncio cũng là lựa chọn tốt.

Thực tế: NumPy, pandas, và hầu hết các ML libraries (XGBoost, LightGBM, scikit-learn) đều release GIL khi chạy các tính toán nặng trong C/C++/Fortran, nên đây không phải vấn đề lớn với data processing thông thường. Python 3.13+ có Free-Threaded mode (tắt GIL) vẫn đang trong giai đoạn experimental.

Giảm Chiều và Học Không Giám sát

Câu 23: PCA, t-SNE và UMAP — khi nào dùng cái nào?

| Phương pháp | Tuyến tính | Bảo toàn Cấu trúc Toàn cục | Tốc độ (100K điểm) | Trường hợp Sử dụng | |------------|-----------|--------------------------|-------------------|-------------------| | PCA | Có | Có | Giây | Tiền xử lý, giảm chiều | | t-SNE | Không | Không | Phút | Trực quan hóa cụm (dữ liệu nhỏ) | | UMAP | Không | Một phần | Giây | Trực quan hóa + tiền xử lý |

PCA: Phép biến đổi tuyến tính tìm các hướng variance lớn nhất. Deterministic, nhanh, bảo toàn global structure (khoảng cách tương đối giữa các cluster). Phù hợp cho preprocessing trước khi train model, và khi cần explainability (mỗi principal component là linear combination của features gốc).

t-SNE: Thuật toán phi tuyến tập trung vào bảo toàn local structure (các điểm gần nhau trong không gian gốc vẫn gần nhau sau khi giảm chiều). Tuyệt vời cho visualization nhưng có nhược điểm: chậm với dữ liệu lớn, không deterministic, và khoảng cách giữa các cluster không có ý nghĩa toán học. Không thể dùng để transform data mới (non-parametric).

UMAP: Nhanh hơn t-SNE đáng kể, bảo toàn một phần global structure, và có thể transform data mới (parametric mode). Trong thực tế đã dần thay thế t-SNE cho hầu hết use cases. Tuy nhiên, kết quả phụ thuộc vào hyperparameters n_neighborsmin_dist.

Câu 24: K-means thất bại trong trường hợp nào và các thuật toán thay thế là gì?

K-means có những giả định ngầm quan trọng có thể bị vi phạm:

Clusters hình cầu (spherical): K-means tối ưu hóa inertia (sum of squared distances to centroid), giả định clusters có hình dạng cầu và kích thước tương đương. Clusters hình vòng, hình lưỡi liềm, hay elongated sẽ bị phân tích sai.

Cần chỉ định K trước: Không biết số clusters là bất lợi lớn. Elbow method và silhouette score giúp nhưng không phải lúc nào cũng rõ ràng.

Nhạy cảm với outliers: Outliers kéo centroids xa khỏi cluster thực.

Không xử lý được clusters với mật độ khác nhau hoặc clusters không linearly separable.

Các thuật toán thay thế:

  • DBSCAN (Density-Based): Tìm clusters dựa trên mật độ, không cần chỉ định K, tự nhiên phát hiện outliers (noise points), xử lý được clusters hình dạng phức tạp. Nhược điểm: nhạy cảm với hyperparameters epsmin_samples, khó scale với dữ liệu rất lớn.
  • GMM (Gaussian Mixture Models): Mô hình xác suất cho phép clusters hình ellipse, cung cấp soft assignment (xác suất thuộc mỗi cluster). Phù hợp hơn khi cần uncertainty quantification.
  • Spectral Clustering: Dựa trên eigenvectors của similarity matrix, xử lý được clusters phi tuyến tính. Tốt với small-to-medium datasets.

Giao tiếp và Tác động Kinh doanh

Câu 25: Giải thích feature importance cho các stakeholder phi kỹ thuật bằng SHAP values như thế nào?

Đây là câu hỏi đánh giá khả năng communication của data scientist, không chỉ kiến thức kỹ thuật.

SHAP (SHapley Additive exPlanations) dựa trên game theory (Shapley values), phân phối "đóng góp" của mỗi feature vào dự đoán của model một cách công bằng — có nền tảng toán học vững chắc, nhất quán, và có thể so sánh được giữa các models khác nhau.

Ưu điểm kỹ thuật: Local explainability (giải thích từng dự đoán cụ thể), global explainability (tổng hợp qua toàn bộ dataset), và interaction effects. Hỗ trợ TreeExplainer (nhanh, chính xác cho tree models), LinearExplainer, DeepExplainer (cho neural networks).

Cách trình bày với stakeholders phi kỹ thuật: Thay vì nói "SHAP value của feature X là 0.23", hãy dịch sang ngôn ngữ kinh doanh: "Thu nhập hàng tháng trên 15 triệu VND tăng xác suất chấp thuận khoản vay thêm 18% so với mức trung bình." Sử dụng waterfall plots (cho từng quyết định) và beeswarm plots (cho overview toàn dataset) để visualization trực quan.

python
# feature_importance_shap.py
import shap
import xgboost as xgb
from sklearn.datasets import make_classification

# Generate synthetic dataset
X, y = make_classification(n_samples=1000, n_features=10,
                           n_informative=5, random_state=42)

# Train XGBoost model
model = xgb.XGBClassifier(n_estimators=100, random_state=42, eval_metric='logloss')
model.fit(X, y)

# SHAP explanation
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)

# Global importance: mean absolute SHAP value per feature
import numpy as np
importance = np.abs(shap_values).mean(axis=0)
for i in np.argsort(importance)[::-1]:
    print(f"Feature {i}: {importance[i]:.4f}")

Kết luận

Việc chuẩn bị toàn diện cho phỏng vấn Data Science đòi hỏi nắm vững cả chiều rộng lẫn chiều sâu — từ nền tảng thống kê đến triển khai hệ thống production. Những điểm cốt lõi cần ghi nhớ:

  • Thống kê và xác suất không chỉ là lý thuyết — luôn kết nối với quyết định thực tế (cỡ mẫu, alpha, power).
  • Feature engineering thường tạo ra sự khác biệt lớn hơn việc chọn thuật toán — hiểu cơ chế missing data và encoding là bắt buộc.
  • Đánh giá mô hình phải phù hợp với bài toán kinh doanh: imbalanced data cần AUPRC, time series cần TimeSeriesSplit.
  • Data leakage là kẻ thù vô hình của mọi data scientist — luôn dùng Pipeline và cảnh giác với temporal ordering.
  • Deep learning không phải magic: hiểu trade-offs (ReLU vs GELU, fine-tuning vs feature extraction) thể hiện sự trưởng thành kỹ thuật.
  • Communication là skill bị đánh giá thấp nhưng quan trọng không kém kỹ thuật — khả năng giải thích SHAP values cho CFO có giá trị ngang với biết implement Transformer từ đầu.
  • Production mindset: Mọi mô hình cuối cùng đều cần scale, monitor, và handle drift. Câu hỏi về feature stores, A/B testing, và concept drift không còn là "advanced" — chúng là tiêu chuẩn tối thiểu cho senior roles.

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ẻ

#data-science
#interview
#machine-learning
#statistics
#python

Chia sẻ

Bài viết liên quan