Module 5 - Project 5.1
1. Giới thiệu bài toán
Project này được thực hiện với bộ dữ liệu "Ames Housing" mô tả các giao dịch nhà ở tại thành phố Ames, Iowa, Mỹ, trong khoảng thời gian 2006–2010.
Mục tiêu bài toán là với các đặc trưng (features) đã cho của một ngôi nhà và bất động sản liên quan, đưa ra dự đoán giá bán (“SalePrice”).
Bộ dữ liệu gồm 79 đặc trưng với các kiểu dữ liệu khác nhau: kiểu số (numerical), kiểu phân loại (categorical), kiểu thứ tự (ordinal), kiểu rời rạc (discrete).
Một số thách thức chính có thể kể đến của bài toán như:
- Biến có nhiều kiểu dữ liệu khác nhau: có nhiều cột là kiểu phân loại (categorical) cần được mã hoá (encoding) phù hợp
- Nhiều giá trị thiếu: nhiều đặc trưng có rất nhiều giá trị bị thiếu (trên 50%) hoặc bị ghi lại theo cách “không có” -> Cần có cách xử lý (imputation) phù hợp
- Phân phối lệch: một số biến số có phân phối skewed, ảnh hưởng đến các mô hình tuyến tính -> có thể áp dụng một số phương pháp transformation các đặc trưng cho các mô hình tuyến tính.
- Nhiều giá trị ngoại lai (Outliers): Một số căn nhà có giá cực cao, gây khó khăn cho quá trình huấn luyện -> có thể áp dụng một số phương pháp chuẩn hóa ít nhạy cảm với ngoại lai.
2. Cở sở lý thuyết
Dựa trên baseline cơ bản được đề xuất, ta sẽ lần lượt tìm hiểu các giải pháp ở mỗi bước sau:
2.1. Xử lý dữ liệu thiếu (Imputation)
Với các cột số (numeric), Simple Imputer (mean/ median) thường được sử dụng để dự đoán giá trị còn thiếu (missing values). Một số kỹ thuật nâng cao có thể áp dụng như KNN Imputer hay Iterative Imputer, đặc biệt khi có nhiều đặc trưng tương quan, ta có thể dự đoán giá trị bị thiếu dựa vào các cột khác. Trong đó:
- KNN Imputer: sẽ tìm $k$ láng giềng gần nhất (theo khoảng cách) của từng mỗi còn thiếu, sau đó tính trung bình giá trị của các láng giềng để điền vào.
- Iterative Imputer: sẽ hoạt động như một mô hình hồi quy:
- Chọn một cột có missing values làm biến đích (target).
- Dùng các cột còn lại làm feature để huấn luyện mô hình hồi quy dự đoán phần giá trị thiếu.
Với các cột categorical, nếu số lượng giá trị thiếu vượt quá 50%, khi đó cột sẽ ít cung cấp thông tin cho bài toán và ta tiến hành bỏ các cột này. Với các cột còn lại, có thể thay thế giá trị NaN bằng 'None' hoặc 'Missing' tuỳ ngữ cảnh (ví dụ: BsmtQual, BsmtCond, BsmtExposure, BsmtFinType1, BsmtFinType2: NA điền bằng "NoBasement").
2.2. Xử lý dữ liệu lệch (skewness)
Bộ dữ liệu này có một vài đặc trưng (bao gồm cả target) có phân phối bị lệch phải.
Do đó, ta cần một số phương pháp biến đổi dữ liệu (transformation) giúp phân phối của dữ liệu trở nên gần đối xứng hơn, giúp mô hình học ổn định và tăng độ tuyến tính giữa các đặc trưng và biến đầu ra (đặc biệt với các mô hình tuyến tính).
Một số phương pháp biến đổi phổ biến:
- Log Transformation: theo công thức:
$$x' = log(1+x)$$
Các biến đổi này giúp nén các giá trị lớn, làm giảm ảnh hưởng của các outlier đến mô hình. Trong thư viện numpy có hỗ trợ hàm numpy.log1p cho biến đổi này. Tuy nhiên, biến đổi này không áp dụng được cho dữ liệu có giá trị âm hoặc 0.
- Biến đổi Box-Cox (Box-cox transformation): theo công thức:
$$x' = \frac{x^\lambda-1}{\lambda}$$
Với $\lambda$ được ước lượng sao cho phân phối gần chuẩn nhất. Box-cox transformation cũng không áp dụng được khi có giá trị 0 hoặc âm.
- Biến đổi Yeo-johnson (Yeo-johnson transformation): theo công thức:
$$\begin{align*} T(y; \lambda) &= \begin{cases} \dfrac{(y + 1)^{\lambda} - 1}{\lambda}, & \text{if } \lambda \ne 0, \\\\ \log(y + 1), & \text{if } \lambda = 0 \end{cases} \quad &\text{for } y \ge 0, \\\\[10pt] T(y; \lambda) &= \begin{cases} -\dfrac{(-y + 1)^{2 - \lambda} - 1}{2 - \lambda}, & \text{if } \lambda \ne 2, \\\\ -\log(-y + 1), & \text{if } \lambda = 2 \end{cases} \quad &\text{for } y < 0. \end{align*}$$
Một ưu điểm của biến đổi Yeo-johnson so với 2 biến đổi trên là nó có thể hoạt động được cho dữ liệu âm, 0, dương. Cả 2 phương pháp Box-cox và Yeo-johnson đều được cài sẵn trong sklearn.preprocessing.PowerTransformer với tham số method (chọn method là "yeo-johnson" hoặc "box-cox").
Trong thực nghiệm, với các biến đổi như Box-cox hay log, ta cần đưa ngưỡng nhỏ nhất data (clip data) về 1 khoảng lớn 0 (ví dụ: cắt ngưỡng min của data = $10^{-6}$)
2.3. Mã hóa đặc trưng phân loại (encoding)
Bộ dữ liệu này có hơn 40% đặc trưng có kiểu categorical (nhãn, chuỗi, ...). Do đó, cần có các kỹ thuật mã hóa phù hợp.
Với một số đặc trưng như HeatingQC, KitchenQual, FireplaceQu, GarageQual, ... là các biến có thứ bậc, do đó ta sẽ dùng Ordinal Encoder cho các đặc trưng này.
Với các đặc trưng còn lại, ta có thể sử dụng các kỹ thuật phổ biến như One Hot Encoder hay Target Encoder.
-
One Hot Encoder: là một kỹ thuật dễ hiểu và dễ triển khai. Tuy nhiên, nó làm tăng mạnh số chiều và gây ra "curse of dimensionality" (tạm dịch: lời nguyền của tính đa chiều) làm mô hình chậm hơn. Đồng thời, nó cũng tạo ra feature sparse làm giảm hiệu năng của các mô hình dựa trên khoảng cách như KNN.
-
Target Encoder: mỗi nhãn (category) được thay thế bằng giá trị trung bình của biến mục tiêu (target) tương ứng. Ví dụ: dự đoán
SalePrice, ta tính:
$$\text{Encoding}(x_i) = \dfrac{\operatorname{Mean}(SalePrice \mid Category = x_i)} {\operatorname{Global\ Mean}(SalePrice)}$$
Hoặc có thể tính đơn giản:
$$\text{Encoding}(x_i) = \operatorname{Mean}(SalePrice | Category = x_i)$$
Để sử dụng TargetEncoder, ta cần cài đặt thư viện category_encoders và import như sau:
from category_encoders import TargetEncoder
Với TargetEncoder, có 1 chỉ số (tham số, parameter) cần quan tâm là smothing. Giá trị Encoded khi có smothing được tính theo công thức:
$$ \text{EncodedValue} = \frac{n_i \times \text{mean}_i + \alpha \times \text{global\_mean}}{n_i + \alpha} $$
Trong đó:
- $n_i$: số mỗi có nhãn (category) $i$
- $\alpha$: hệ số smothing, thường là $1-100$
- $\text{mean}_i$: trung bình target nhãn $i$
- global mean: trung bình target toàn bộ dữ liệu
Có thể thấy rằng:
- $\alpha$ nhỏ sẽ nhạy cảm với trung bình từng nhóm
- $\alpha$ lớn kết quả càng mượt hơn do bị chi phối mạnh bởi trung bình toàn dữ liệu.
2.4. Chuẩn hóa dữ liệu (scaling)
Trong dữ liệu thô, các đặc trưng thường có đơn vị và phạm vi giá trị khác nhau. Nếu không chuẩn hoá, mô hình có thể coi trọng quá mức các đặc trưng có giá trị lớn (như diện tích) và bỏ qua các đặc trưng nhỏ (như chất lượng). Do đó, ta cần đưa tất cả đặc trưng về cùng một thang đo để giúp mô hình học hiệu quả và ổn định hơn.
Một số kỹ thuật chuẩn hóa phổ biến như:
- Min Max Scaler: theo công thức:
$$x' = \frac{x - x_{\min}}{x_{\max} - x_{\min}}$$
Giá trị được đưa về phạm vi $[0, 1]$. Tuy nhiên, phương pháp này rất nhạy cảm với outlier, nếu có một điểm dữ liệu cực lớn, toàn bộ dữ liệu khác sẽ bị “nén” lại gần 0.
- Standard Scaler: theo công thức:
$$x' = \frac{x - \mu}{\sigma}$$
Giá trị được đưa về phân phối chuẩn (có $mean = 0$ và $std = 1$). Phương pháp này phù hợp với hầu hết mô hình tuyến tính và giúp tối ưu gradient descent hội tụ nhanh hơn.
- Robust Scaler: theo công thức:
$$x' = \frac{x - \operatorname{Median}(x)}{IQR}$$
Với $IQR = Q_3 - Q_1$. Kỹ thuật này rất bền vững với outlier nhưng không thể giới hạn dữ liệu trong khoảng cụ thể (như $[0,1]$).
2.5. Xử lý ngoại lai (outlier handling)
Trong bộ dữ liệu thường chứa một vài điểm dữ liệu có các giá trị bất thường. Các điểm dữ liệu này sẽ làm sai lệch trung bình, phương sai, và hệ số hồi quy, từ đó gây mất ổn định cho mô hình, đặc biệt là các thuật toán tuyến tính.
Một số kỹ thuật xử lý ngoại lai phổ biến như:
- Cắt giá trị bằng IQR (IQR Clipping): một giá trị $x$ được xem là ngoại lai nếu:
$$x < Q_1 - 1.5*IQR \qquad \text{hoặc} \qquad x > Q_3 + 1.5*IQR$$
Khi đó, các giá trị ngoại lai sẽ được cắt về ngưỡng biên. Tuy nhiên, kỹ thuật này có thể loại bỏ dữ liệu hợp lệ nếu dữ liệu phân phối lệch.
- Winsorization: kỹ thuật này sẽ thay thế các giá trị ngoại lai bằng các giá trị tại các percentile cụ thể. Ví dụ: cắt $1\%$ nhỏ nhất và $1\%$ lớn nhất
from scipy.stats.mstats import winsorize
X['GrLivArea'] = winsorize(X['GrLivArea'], limits=[0.01, 0.01])
Khi đó, mọi giá trị nhỏ hơn $P_1$ được thay bằng $P_1$, và lớn hơn $P_{99}$ được thay bằng $P_{99}$. Kỹ thuật này giúp giảm ảnh hưởng của outlier mà không mất nhiều thông tin, tuy nhiên cũng cần chọn tỷ lệ cắt (ví dụ $1\%$, $2\%$) hợp lý.
- z-score: một điểm được coi là ngoại lai nếu $|z| > 3$, với:
$$z = \frac{x - \mu}{\sigma}$$
Tuy nhiên, kỹ thuật này chỉ phù hợp khi dữ liệu có phân phối chuẩn (Gaussian). Nó không phù hợp nếu dữ liệu lệch, nó cũng bị ảnh hưởng mạnh bởi outlier chính nó (vì mean và std cũng bị ảnh hưởng bởi outlier).
2.6. Xử lý đa cộng tuyến (multicollinearity handling)
Đa cộng tuyến (Multicollinearity) là hiện tượng khi hai hoặc nhiều đặc trưng (feature) trong tập dữ liệu có tương quan tuyến tính mạnh với nhau.
Hiện tượng này làm hệ số hồi quy ước tính có sai số chuẩn cao hay có thể hiểu là mô hình không thể xác định rõ ràng tác động của từng biến độc lập lên biến phụ thuộc vì các biến này có thể đang "kể cùng một câu chuyện".
Ta có thể kiểm tra điều này bằng các chỉ số như ma trận tương quan (correlation matrix), VIF (Variance Inflation Factor), MI (Mutual Information), ...
- Correlation matrix: là ma trận thể hiện hệ số tương quan
$r$ giữa mọi cặp đặc trưng:
$$r_{xy}= \frac{\operatorname{Cov}(x,y)}{\sigma_x\sigma_y}$$
Nếu $|r| > 0.8$ thì 2 đặc trưng có khả năng đa cộng tuyến.
- VIF (Variance Inflation Factor): là chỉ số đo mức độ của một biến mức độ phương sai của hệ số hồi quy ước tính tăng lên do tính đa cộng tuyến. VIF được xác định bằng công thức:
$$VIF_i = \frac{1}{1-R_i^2}$$
Với $R_i^2$ là hệ số xác định (R-squared) khi biến $i$ được hồi quy bằng các biến còn lại. $R_i^2$ cao nghĩa là có mối tương quan mạnh giữa các đặc trưng khác với đặc trưng đang xét, dẫn đến $VIF$ cao (thường $> 10$), khiến cho việc dự đoán đóng góp của nó vào mô hình sẽ khó khăn hơn, hay nói cách khác là mức độ đa cộng tuyến cao. $VIF < 5$ thường là mức chấp nhận được.
VIF được cài sẵn trong thư viện statsmodels. Ta có thể sử dụng bằng cách import:
from statsmodels.stats.outliers_influence import variance_inflation_factor
- Mutual Information (MI): đo lường mức độ phụ thuộc giữa hai biến — không chỉ tuyến tính mà cả phi tuyến.
MI bằng 0 cho thấy hai biến độc lập hoàn toàn. MI càng cao cho thấy hai biến phụ thuộc mạnh. Không giống như VIF, MI không có ngưỡng chuẩn. Tuy nhiên nó có thể phát hiện được cả quan hệ phi tuyến.
MI được cài sẵn trong thư viện sklearn. Ta có thể sử dụng bằng cách import:
from sklearn.feature_selection import mutual_info_regression
Một số kỹ thuật thường dùng để xử lý đa cộng tuyến bao gồm:
-
Loại bỏ các đặc trưng có tương quan cao: dựa vào các chỉ số Correlation Matrix, VIF,... hoặc sử dụng các kỹ thuật feature selection
-
Kết hợp các biến để giữ lại thông tin cốt lõi: Ví dụ: thay vì giữ 2 biến
YrSoldvàGarageYrBlt, ta có thể tạo ra biến:
$$\text{GarageAge} = \text{YrSold} - \text{GarageYrBlt}$$ -
Sử dụng các thuật toán giảm chiều: như PCA để thu được các vector không tương quan. Tuy nhiên, cách này sẽ làm mất ý nghĩa diễn giải của biến gốc.
2.7. Mô hình (Modeling)
Sau khi đã tối ưu giai đoạn tiền xử lý (preprecossing), ta sẽ tiến hành tối ưu mô hình, cụ thể là việc chọn lựa các mô hình thử nghiệm khác nhau và kết hợp chúng (ensemble/ stacking).
2.7.1. Lựa chọn mô hình
Các mô hình được lựa chọn trong bài toán này bao gồm:
| Mô hình | Đặc điểm |
|---|---|
| Linear Regression | Đơn giản, dễ diễn giải. Nhưng nhạy cảm với ngoại lai và cho hiệu quả tốt khi dữ liệu được chuẩn hóa và đa cộng tuyến đã được xử lý. |
| Ridge Regression | Sử dụng L2 regularization để giảm overfitting, ổn định hơn Linear Regression |
| Lasso Regression | Dùng L1 regularization để giảm overfitting, có thể ép hệ số của các đặc trưng ít đóng góp về 0 |
| ElasticNet | Kết hợp cả L1 (Lasso) và L2 (Ridge). Khi dữ liệu có nhiều biến tương quan chéo, ElasticNet giúp cần cân bằng giữa tính chọn lọc biến của Lasso và tính ổn định của Ridge. |
| Huber Regressor | Dùng hàm mất mát Huber, kết hợp giữa MSE (cho lỗi nhỏ) và MAE (cho lỗi lớn). Huber không bị ảnh hưởng mạnh bởi ngoại lai. |
| Quantile Regressor | Thay vì dự đoán giá trung bình, mô hình này học để dự đoán phân vị (quantile), ví dụ 0.5 (median), 0.9 (giá cao). Phù hợp khi phân phối giá nhà bị lệch (skewed). |
| RANSAC Regressor | Đây là thuật toán lặp với mỗi vòng lặp, nó cố gắng ước lượng tham số mô hình (sử dụng 1 base model như Linear Regression hay Ridge) tối ưu sao cho phù hợp với phần lớn dữ liệu “tốt” (inliers). Từ đó giúp tránh việc bị "kéo lệch" bởi các điểm bất thường. Vì thế, nó cực kỳ bền vững với outlier. |
| Random Forest | Kết hợp nhiều Decision Tree độc lập, mỗi cây học trên một "lát cắt" của dữ liệu. Từ đó, nó dễ dàng nắm bắt mối quan hệ phi tuyến giữa các biến trong dữ liệu. |
| Gradient Boosting | Xây dựng cây mới để sửa lỗi của cây trước (boosting) dựa trên gradient. Tuy nhiên, cần kiểm soát để tránh overfitting |
| AdaBoost | Một mô hình nhóm boosting, ở mỗi cây sau, mẫu bị dự đoán sai được “nhấn mạnh” hơn dựa trên việc điều chỉnh trọng số mẫu. |
| XGBoost | Một phiên bản tối ưu của Gradient Boosting nhờ các cơ chế regularization, tree pruning, tính toán song song, ... |
| LightGBM | Dựa trên Gradient Boosting, nhưng chia cây theo độ sâu lá (leaf-wise) thay vì mức (level-wise). |
| CatBoost | Một dạng Gradient Boosting được thiết kế đặc biệt để xử lý biến phân loại mà không cần one-hot encoding. |
Bảng 1. Danh sách các mô hình được lựa chọn thử nghiệm
2.7.2. Kết hợp mô hình
Sau khi đã chọn lựa được mô hình, ta sẽ thực hiện kết hợp dự đoán của các mô hình để tối ưu hơn kết quả dự đoán. Các kỹ thuật được sử dụng phổ biến bao gồm: Voting, Stacking, Blending, ...
-
Voting/ Averaging: là 1 cách kết hợp thuộc nhóm Ensemble, với ý tưởng rằng "kết quả trung bình của các dự đoán đó sẽ ổn định hơn một mô hình đơn lẻ". Có 2 chiến lược Averaging phổ biến:
-
Simple Averaging: là cách tính trung bình cơ bản. Khi đó với $n$ mô hình, mỗi mô hình đều có trọng số bằng nhau là $1/n$.
-
Weighted Averaging: mỗi mô hình được gán trọng số khác nhau, mô hình mạnh hơn có tiếng nói lớn hơn. Trong bài toán này, trọng số (weight) sẽ được tính đơn giản là $1/rmse$. Sau đó, trọng số sẽ được chuẩn hóa bằng có:
$$weight_i' = \frac{weight_i}{\sum_{i=1}^{n} weight_i}$$
-
-
Stacking: ta huấn luyện một meta-model (mô hình cấp cao hơn, ví dụ như Linear Regression hay Ridge) để học cách kết hợp các mô hình con sao cho sai số nhỏ nhất. Quy trình Stacking được thực hiện như sau:
-
Bước 1: Huấn luyện các mô hình gốc trên dữ liệu ban đầu bằng cross validation. Từ đó, thu được dự đoán validation cho từng mẫu, các dự đoán này được gọi là OOF (Out-of-fold) predictions.
-
Bước 2: Dùng các dự đoán này làm đặc trưng đầu vào (features) cho mô hình meta.
-
Bước 3: Huấn luyện mô hình meta để dự đoán giá cuối cùng.
-
-
Giải thuật leo đồi (Hill Climbing): một phương pháp heuristic (tối ưu tham lam) giúp tự động tinh chỉnh trọng số của từng mô hình. Hill Climbing bắt đầu từ trọng số đều cho các mô hình con và liên tục điều chỉnh một chút để xem có cải thiện RMSE hay không. Do điều chỉnh từng bước nhỏ nên Hill Climbing dễ mắc kẹt tại cực trị cục bộ (local optimum).
Do đặc tính trên của Hill Climbing nên trong bài toán này, Hill climbing sẽ được sử dụng để tìm các thông số (parameters) để đạt cực trị cục bộ, các parameters này trước đó đã được sàng lọc sơ bộ bởi optuna.
3. Thực nghiệm và các nhận xét về bài toán
Nhóm tiến hành cải thiện bài toán dựa trên pipeline sau:
$$\text{Khám phá dữ liệu} \rightarrow \text{Tiền xử lý dữ liệu} \rightarrow \text{Mô hình}$$
3.1. Khám phá dữ liệu (Explore data analysis - EDA)
3.1.1. Khám phá dữ liệu
Kiểm tra sơ bộ
Ở bước này, ta sẽ lần lượt kiểm tra sơ bộ:
- Số lượng đặc trưng, mẫu
- Số cột bị trùng lắp
- Số cột bị thiếu dữ liệu
- Số lượng nhãn của các cột categorical
Khám phá biến đích (target)
Ta sẽ đi sâu hơn vào biến target. Đầu tiên, ta quan sát phân phối, độ lệch của biến target và các dạng biến đổi của nó để các bước sau có các chiến lược biến đổi dữ liệu hợp lý hơn.

Hình 1. Phân phối của biến target

Hình 2. Thử nghiệm log transformation cho biến target
Có thể thấy rằng, biến target có phân phối lệch phải. Khi áp dụng biến đổi log vào biến target, chỉ số skewness đã cải tiến đáng kể, từ đó ta có thể xem xét biến đổi log và các phép biến đổi khác để chuẩn hóa lại phân phối biến target.
Đồng thời cũng sẽ kiểm tra tương quan giữa biến target và các đặc trưng bằng ma trận tương quan.

Hình 3. Ma trận tương quan giữa top 10 đặc trưng có hệ số tương quan cao với biến target
Khám phá các đặc trưng
Sau khi đã khám phá biến target, ta chuyển sang quan sát cho các đặc trưng. Hai điểm cần quan tâm của các đặc trưng là độ lệch và tình trạng đa cộng tuyến.
Đầu tiên, ta sẽ kiểm tra và in ra các đặc trưng có độ lệch cao ($>2$):
# house_df là DataFrame của bộ dữ liệu
numeric_cols = house_df.select_dtypes(include=['float64', 'int64']).columns.tolist()
for col in numeric_cols:
if house_df[col].skew() > 2:
print(f"Col {col} | Skewness: {house_df[col].skew()}")
Kết quả của đoạn code trên:

Hình 4. Các đặc trưng có phân phối bị lệch
Có thể thấy, với bộ dữ liệu này, có khá nhiều đặc trưng bị lệch. Do đó, ta sẽ cần biến đổi input để giảm tình trạng này.
Để kiểm tra vấn đề đa cộng tuyến giữa các đặc trưng, ta sẽ sử dụng chỉ số VIF và MI:
| Feature | VIF | |
|---|---|---|
| 8 | BsmtFinSF1 | inf |
| 9 | BsmtFinSF2 | inf |
| 10 | BsmtUnfSF | inf |
| 11 | TotalBsmtSF | inf |
| 15 | GrLivArea | inf |
| 14 | LowQualFinSF | inf |
| 13 | 2ndFlrSF | inf |
| 12 | 1stFlrSF | inf |
| 35 | YrSold | 2.411126e+04 |
| 24 | GarageYrBlt | 2.290578e+04 |
Bảng 2. Kiểm tra các đặc trưng đa cộng tuyến bằng VIF trong bộ dữ liệu
| Feature | MI_Score | |
|---|---|---|
| 0 | OverallQual | 0.562764 |
| 1 | GrLivArea | 0.483217 |
| 2 | YearBuilt | 0.367590 |
| 3 | TotalBsmtSF | 0.366366 |
| 4 | GarageArea | 0.364472 |
| 5 | GarageCars | 0.360555 |
| 6 | 1stFlrSF | 0.310100 |
| 7 | GarageYrBlt | 0.289572 |
| 8 | MSSubClass | 0.273448 |
| 9 | FullBath | 0.260504 |
Bảng 3. Kiểm tra các đặc trưng đa cộng tuyến bằng MI
Dựa vào các kết quả minh họa dựa trên VIF và MI, có thể bộ dữ liệu có nhiều đặc trưng có tình trạng đa cộng tuyến cao ($VIF = inf$ hay MI cao). Ở các bước sau, ta cần có các chiến lược Feature Engineering và Feature Selection để giải quyết vấn đề này.
3.1.2. Loại bỏ các cột thiếu dữ liệu
Tiếp theo, ta xem xét một thách thức khác của bộ dữ liệu này là vấn đề thiếu dữ liệu.

Hình 5. Các đặc trưng bị thiếu dữ liệu
Dựa vào đồ thị trên, ta thấy rằng nhiều đặc trưng bị thiếu hơn 50% dữ liệu. Một số tài liệu cho rằng, một số cột như PoolQC, các giá trị nan thực chất là NoPool. Nhưng trong lần thử nghiệm này, nhóm quyết định sẽ loại bỏ các cột có hơn 50% giá trị bị thiếu để tránh ảnh hưởng đến kết quả cải tiến.
3.1.3. Feature Engineering
Đầu tiên, ta sẽ tiến hành xử lý các giá trị thiếu và mã hóa (ánh xạ) giá trị cho một số đặc trưng, đặc biệt là các đặc trưng liên quan đến chất lượng (Quality và Condition) do các đặc trưng này có tính thứ bậc. Với các giá trị bị thiếu sẽ được điền là No, NoBasement (cho các đặc trưng liên quan đến tầng hầm (Basement, trong bộ dữ liệu sẽ bắt đầu bằng bsmt) hoặc sẽ được ánh xạ với giá trị $0$. Kỹ thuật encoding được chọn cho các đặc trưng này là Ordinal Encoding.
Các cột chất lượng được ánh xạ như sau:
| Giá trị | Viết đầy đủ | Ánh xạ |
|---|---|---|
| Ex | Excellent | 5 |
| Gd | Good | 4 |
| TA | Typical / Average | 3 |
| Fa | Fair | 2 |
| Po | Poor | 1 |
| NA | No Basement | 0 |
Bảng 4. Bảng mã hóa giá trị các đặc trưng chất lượng
Với các đặc trưng về diện tích, tuổi, chất lượng, tiện ích sẽ được tổng hợp (aggregation) lại để giảm tình trạng đa cộng tuyến. Ví dụ:
# raw_data là dữ liệu đã xóa các cột thiếu dữ liệu
FE_house_df = raw_data.copy()
FE_house_df['TotalArea'] = FE_house_df[['GrLivArea', 'TotalBsmtSF','GarageArea']].sum(axis=1)
FE_house_df['LivingToLotRatio'] = FE_house_df['GrLivArea'] / FE_house_df['LotArea']
Sau khi đã Feature Engineering, ta có thể kiểm tra sơ bộ tình trạng đa cộng tuyến bằng VIF. Kết quả cho thấy đã không còn các cột có giá trị VIF là inf.
| Feature | VIF | |
|---|---|---|
| 29 | TotalArea | 1306.588174 |
| 31 | TotalFinSF | 692.038708 |
| 23 | GarageCond | 268.584393 |
| 39 | HasGarage | 268.457117 |
| 22 | GarageQual | 261.346499 |
| 40 | HasBsmt | 207.469995 |
| 42 | IsPaved | 159.792866 |
| 7 | BsmtCond | 125.231442 |
| 36 | OverallScore | 115.580544 |
| 4 | ExterQual | 109.558916 |
Bảng 5. Top 10 VIF sau Feature Engineering
3.1.4. Lựa chọn đặc trưng (Feature Selection)
Sau khi đã hoàn thành các bước trên, ta tiến thêm 1 bước để cải thiện hơn nữa vấn đề đa cộng tuyến bằng Feature Selection.
Trong bước này, nhóm thực hiện hybrid selection (tạm dịch: lai chọn lọc) giữa 5 mô hình khác nhau và chỉ giữ lại các đặc trưng được ít nhất 3/5 phương pháp cùng chọn. Bộ dữ liệu sẽ đi qua 3 mô hình cây (LGBM, XGBoost và Random Forest), LassoCV và thống kê đơn biến (Select KBest):
-
Ba mô hình ensemble tree-based: có ưu điểm là tự động đánh giá độ quan trọng của từng đặc trưng dựa trên mức độ giảm impurity hoặc gain trong quá trình phân tách cây (sử dụng phương thức
feature_importances_được xây dựng sẵn của các mô hình). -
Lasso Regression (L1 Regularization): không chỉ là mô hình hồi quy, mà còn là công cụ hiệu quả để chọn lọc đặc trưng tuyến tính. Nhờ khả năng “ép” hệ số của những biến ít đóng góp về 0, nhờ đó tự động loại bỏ chúng khỏi mô hình.
-
Select KBest: tính mối quan hệ giữa từng biến độc lập và biến mục tiêu (SalePrice) bằng phép kiểm định thống kê F-test. Khi đó, những biến có tương quan mạnh nhất (giá trị F lớn) được chọn ra. Tuy nhiên, kỹ thuật này chỉ xem xét từng biến riêng lẻ với biến target, không phát hiện tương tác giữa các đặc trưng.
Sau Feature Selection với 2 bộ dữ liệu ban đầu (raw) và bộ dữ liệu đã Feature Engineering, mỗi bộ dữ liệu giữ lại khoảng 30 đặc trưng so với ban đầu.
3.2. Tiền xử lý dữ liệu (Preprocessing)
Đây là giai đoạn quan trọng để cải tiến cho bài toán. Có nhiều bước có thể thư nghiệm ở đây bao gồm: xử lý dữ liệu thiếu (imputation), xử lý ngoại lai (outlier handling), biến đổi dữ liệu (transformation), chuẩn hóa (scaling), xử lý đa cộng tuyến (multicollinearity handling), feature interactions.
Thứ tự được lựa chọn tối ưu như sau:
| Bước | Lý do |
|---|---|
| 1. Outlier Handling | Outlier làm lệch trung bình, median, IQR, phân phối → ảnh hưởng các bước Imputation, Transform, Scaling (lan truyền lỗi) |
| 2. Imputation | Điền giá trị thật để chuẩn bị cho các bước sau |
| 3. Transform | Chuẩn hóa phân phối trước khi scale |
| 4. Scaling | Chuẩn bị dữ liệu cho Linear model, Poly |
| 5. Encoding | Với Target Encoder, cần y sạch và các biến numeric ổn định |
| 6. Polynomial & Interactions | Tạo từ features đã sạch, scale, encode |
| 7. Multicollinearity | Nếu đưa trước interactions → bỏ sót multicollinearity |
Bảng 6. Thứ tự tối ưu trong preprocessing
Chương trình đã tổ chức một hàm tổng quát cho phép đánh giá từng lựa chọn ở mỗi bước và một hàm cho phép tính điểm số để chọn ra giải pháp tối ưu (xem chi tiết ở phần Function for Experients trong file preprocessing.ipynb trong code)
- Hàm đánh giá: như prototype bên dưới:
def evaluate_dataset(
df,
dataset_name,
base_models,
model_groups,
group_name=None,
n_splits=5,
imputer_type="simple",
scaler_type="minmax",
encoder_type="onehot",
outlier_method=None,
input_transform="org",
target_transform="org",
multicol_method=None,
RANDOM_STATE=RANDOM_STATE,
knn_neighbors=5,
target_encoder_smoothing=10,
):
Với hàm này, ta có thể thử nghiệm nhiều bước khác nhau như imputation, scaling, encoding, ... và thử nghiệm nhiều lựa chọn khác nhau ở từng bước
- Hàm tính điểm: như prototype bên dưới:
def compare_experiment_results(base_df, test_dfs, test_names,
group_col="Group", weights=(0.5, 0.2, 0.3)):
Trong đó, weights được sử dụng để tính trọng số cho từng chỉ số lần lượt là Improved_Mean_RMSE, Improved_Std_RMSE, Improved_Mean_R2. Như thông số mặc định, Improved_Mean_RMSE, Improved_Std_RMSE, Improved_Mean_R2 sẽ có trọng số lần lượt là $0.5, 0.2, 0.3$. Giá trị Improved của 1 chỉ số sẽ được tính bằng cách:
-
Giả sử ta thực hiện tính điểm cho TargetEncoder với baseline là OneHotEncoder.
-
Khi đó, giá trị Improved Mean RMSE được tính:
$$ \text{Improved Mean RMSE} = \frac{\operatorname{Mean RMSE}(\text{TargetEncoder})} {\operatorname{Mean RMSE}(\text{OneHotEncoder})} $$
Giá trị score sau khi tính được, nếu:
- Score > 0: giải pháp tốt hơn baseline
- Score < 0: giải pháp tệ hơn baseline
- Score ~ 0: giải pháp không cải thiện nhiều so với baseline (khi đó sẽ chọn baseline)
Nhóm lựa chọn tìm giải pháp tối ưu cho từng nhóm model, vì mỗi model trong 1 nhóm có các đặc tính chung và khác biệt so với các nhóm nhóm khác:
| Nhóm | Đặc điểm |
|---|---|
| Linear Models: gồm có Ridge, Lasso, ElasticNet, Huber, Quantile | Mô hình tuyến tính, cần scale, nhạy outlier |
| Tree Models: gồm có RF, XGB, GB, LGBM, ADB | Không cần scale, ít nhạy outlier, không cần feature selection |
| Special Models: gồm có CatBoost, RANSAC | Có các phương thức xử lý nội tại đặc biệt |
Bảng 7. Danh sách chia nhóm model
Tuy nhiên trước khi bước vào tối ưu preprocessor, ta sẽ chạy thử baseline của AIO đã đề xuất để đánh giá sơ bộ hiệu năng của các mô hình. Có thể thấy hiệu năng của các mô hình hầu hết trong khoảng $27,000 - 40,000$ điểm RMSE. Tuy nhiên, 2 mô hình ElasticNet và Quantile Regressor lại lệch ra khoảng này. Do đó, 2 mô hình này sẽ được tuning sơ bộ để chọn được parameter phù hợp cho các giai đoạn tiếp theo.

Hình 6. Kết quả Mean RMSE baseline các model
Bộ dữ liệu được chọn để sử dụng cho tối ưu là bộ dữ liệu thô (raw) đã được xử lý Feature Selection (raw_FS).
3.2.1. Xử lý ngoại lai
Ở bước này, ta thử nghiệm với 2 giải pháp là IQR Clipping và Winsorization.

Hình 7. Kết quả thử nghiệm các giải pháp xử lý ngoại lai
Có thể thấy IQR cho hiệu quả vượt trội hơn Winsorization và ta sẽ chọn giải pháp này cho các bước tiếp theo.
3.2.2. Xử lý dữ liệu bị thiếu
Ở bước này, ta thử nghiệm với 4 giải pháp là Simple Imputer (mean/ median) (2 giải pháp), KNN Imputer (mặc định $k=5$) và Iterative Imputer.

Hình 8. Kết quả thử nghiệm các giải pháp xử lý dữ liệu thiếu
Có thể thấy rằng, các giải pháp thử nghiệm với 2 nhóm Linear và Special đều không cải thiện hơn so với baseline (Simple Imputer (mean)). Do đó, ta sẽ chọn baseline cho 2 nhóm này.
Với nhóm Tree Model, KNN cho hiệu quả tốt hơn nên ta sẽ tiến hành tìm $k$ tốt nhất.

Hình 9. Tìm k tốt nhất cho KNN Imputer
Sau thử nghiệm, giá trị $k=9$ là giá trị tốt nhất được chọn.
3.2.3. Biến đổi dữ liệu
Ở bước này, ta sẽ tìm các cặp biển đổi input và target tối ưu cho mỗi nhóm. Các biến đổi input và output được thử nghiệm là:
input_tf_tests = [
("None", "org"),
("Log", "log"),
("Sqrt", "sqrt"),
("Yeo", "yeo-johnson")
]
target_tf_tests = [
("None", "org"),
("Log", "log"),
("Sqrt", "sqrt"),
("Yeo", "yeo-johnson"),
("BoxCox", "box-cox")
]
Sau thử nghiệm, các biến đổi tối ưu cho từng nhóm là:
'input_transform': {'Linear_Models': 'org',
'Tree_Models': 'log',
'Special_Models': 'org'},
'target_transform': {'Linear_Models': 'sqrt',
'Tree_Models': 'org',
'Special_Models': 'log'}
3.2.4. Chuẩn hóa dữ liệu
Ở bước này, ta thử nghiệm với 3 scaler là Min Max Scaler (2 giải pháp), Standard Scaler và Robust Scaler.

Hình 10. Kết quả thử nghiệm các scaler
Có thể thấy rằng, Standard Scaler và Robust Scaler đều góp phần làm giảm RMSE và tăng $R^2$. Tuy nhiên chúng đều có điểm score âm ở cả 3 nhóm, nguyên nhân là do 2 scaler này làm tăng mạnh Std RMSE (1 chỉ số đánh giá trong score).
3.2.5. Mã hóa dữ liệu
Ở bước này, ta thử nghiệm với 2 encoder là One Hot Encoder (2 giải pháp), Target Encoder.

Hình 1. Kết quả thử nghiệm các encoder
Kết quả thử nghiệm cho thấy:
- Target Encoder giúp giảm Mean RMSE ở các nhóm mô hình Tree (2%) và Special (0.9%), score tăng khoảng 2% ở cả 2 nhóm.
- Ở nhóm Linear, Mean RMSE tăng khoảng 0.5% (sẽ làm giảm score theo lý thuyết), tuy nhiên chỉ số score lại tăng 2%, có thể thấy Target Encoder góp phần làm giảm Std RMSE giúp ổn định các mô hình.
- Do đó, Target Encoder sẽ được chọn cho cả 3 nhóm.
3.2.6. Polynomial feature và Interaction
Trong thử nghiệm, ta sẽ đánh giá hiệu quả của polynomial feature với bậc 2. Đặc biệt, ta chỉ thử với nhóm Model do các mô hình ở các nhóm khác đều đã có khả năng nắm bắt quan hệ phi tuyến giữa các đặc trưng.

Hình 12. Kết quả thử nghiệm sử dụng Polynomail Feature
Nhận xét:
- Áp dụng polynomial feature giúp các mô hình tuyến tính nắm bắt thêm các quan hệ phi tuyến tốt hơn thông qua việc giảm Mean RMSE (3%).
- Tuy nhiên, score giảm 4% do Std RMSE tăng rất mạnh, đặc biệt đã cài đặt trọng số tính score khi sử dung polynomial feature là $(0.7,0.1,0.2)$ (mặc định là $(0.5,0.3,0.2)$.
- Do đó, ta không sử dụng polynomial feature cho nhóm Linear.
3.2.7. Xử lý đa cộng tuyến
Dù đã chọn bộ dữ liệu đã Feature Selection trước đó, nhưng nhóm vẫn thử nghiệm để đánh giá hiệu quả của việc bổ sung thêm bước xử lý đa cộng tuyến trong preprocessing. Tương tự polynoimal feature, thử nghiệm cũng chỉ thực hiện cho nhóm Linear và Special.

Hình 13. Kết quả thử nghiệm xử lý đa cộng tuyến
Kết quả cho thấy với:
- Nhóm Special: không bổ sung vẫn là lựa chọn tốt nhất
- Nhóm Linear: việc bổ sung góp phần cải thiện score nhưng hiệu quả không đáng kể (tăng 0.07% score)
- Do đó, nhóm lựa chọn không bổ sung việc xử lý đa cộng tuyến cho cả 2 nhóm.
Tổng kết:
Sau quá trình tối ưu preprocessing, mỗi model đã được cải thiện so với baseline như sau:

Hình 14. Hiệu quả của giai đoạn tối ưu preprocessing so với baseline
3.3. Mô hình (Modeling)
Sau khi đã tối ưu được preprocessing, ta hãy chuyển sang giai đoạn sau cùng là modeling.
Ở giai đoạn này, trước hết, ta sẽ tiến hành fine-tuning để tối ưu từng mô hình với preprocessor tối ưu đã xác định trước đó.
Sau khi đã tinh chỉnh được các thông số tối ưu cho mỗi mô hình, ta sẽ bước vào giai đoạn kết hợp. Hai chiến lược được nhóm sử dụng là Voting (Averaging) và Stacking.
Với mỗi chiến lược, với đầu vào là 4 bộ data (raw, raw_FS, FE, FS_FS), với mỗi bộ data, nhóm sẽ thử nghiệm với 3 bộ model: tất cả model, top 4 các model theo RMSE và top 1 model của từng nhóm theo RMSE. Khi đó, ta sẽ có tất cả :
$$\text{4 bộ data x 3 bộ model x 2 chiến lược = 24 kết quả}$$
Với Voting: nhóm sẽ thực hiện quy trình như sau:
- Sử dụng Weighted Averaging và fine-tuning warm-up bằng
Optuna. - Sử dụng Hill Climbing kết hợp với fine-tuning (2 thông số của Hill Climbing là
step_sizevàmin_improve) với thông số khởi tạo là thông số warm-up. - Đánh giá kết quả.
Với Stacking: nhóm sẽ thực hiện theo quy trình sau:
- Thử nghiệm với nhiều meta learner để chọn learner tốt nhất.
- Fine-tuning để tìm thông số tối ưu nhất cho learner.
- Đánh giá kết quả.

Hình 15. Hiệu quả của voting và stacking so với baseline (model tốt nhất) - Raw data

Hình 16. Hiệu quả của voting và stacking so với baseline (model tốt nhất) - Raw Feature Selection data

Hình 17. Hiệu quả của voting và stacking so với baseline (model tốt nhất) - Feature Engineering data

Hình 18. Hiệu quả của voting và stacking so với baseline (model tốt nhất) - Feature Engineering + Feature Selection data
Từ các kết quả trên có thể thấy rằng:
-
Bộ data: raw data > raw FS data > FE FS data > FE Data
-
Bộ Model và chiến lược kết hợp:
- Voting cho kết quả cải thiện hơn ban đầu nhưng không đáng kể.
- Stacking cho hiệu quả tốt nhất theo thứ tự: tất cả model > Top 4 Global > Top mỗi nhóm
Với bộ raw data (kết quả tốt nh, ta xem xét thêm đóng góp trong Weighted Averaging và tương quan trong Stacking:

Hình 19. Trọng số đóng góp của từng model trong Weighted Averaging

Hình 20. Tương quan giữa các mô hình trong Stacking
Nhận xét:
- Việc thử nghiệm Feature Engineering và Feature Selection không đem nhiều kết quả như mong đợi. Kết quả không tốt hơn bộ raw data có thể do làm mất 1 số thông tin của dữ liệu.
- Weighted Averaging: CatBoost, XGB Quantile đóng góp chủ đạo vào hiệu suất tổng thể. Quantile và RANSAC góp phần làm tăng tính ổn định nhờ đặc tính chống nhiễu..
- Stacking: Các mô hình dự đoán có xu hướng tương đồng (correlation > $0.98$) cho thấy meta-learner cũng không học được quá nhiều từ mỗi mô hình.
4. Đánh giá kết quả và hướng phát triển
Đánh giá kết quả:
- Về khám phá dữ liệu: đã khám phá các vấn đề hiện có của bộ dữ liệu, thử nghiệm Feature Engineering và Feature Selection.
- Về tiền xử lý dữ liệu: đã thử nghiệm và tối ưu lựa chọn từng bước của preprocessing
- Về mô hình hóa: đã thử nghiệm nhiều nhóm mô hình, áp dụng kỹ thuật Ensemble để góp phần cải thiện dự đoán so với mô hình đơn lẻ.
- Về hiệu quả tổng thể:
- Mô hình đạt được kết quả RMSE ở mức tốt, có khả năng tổng quát hóa trên tập validation.
- Pipeline được thiết kế linh hoạt, có thể mở rộng hoặc thay đổi các bước tiền xử lý mà không cần sửa đổi toàn bộ mã nguồn.
Hạn chế:
- Bộ dữ liệu có nhiều đặc trưng dạng phân loại, trong khi các mô hình tuyến tính hoặc không tự động học quan hệ phi tuyến dễ bị hạn chế về khả năng biểu diễn.
- Mô hình chưa thử nghiệm sâu các kỹ thuật feature engineering phức tạp
Hướng phát triển:
- Xây dựng một giao diện web nhỏ (Streamlit) cho phép người dùng nhập thông tin ngôi nhà và nhận dự đoán giá.
- Áp dụng Explainable AI (XAI) để giải thích đóng góp của từng đặc trưng, giúp mô hình không chỉ chính xác mà còn minh bạch, hỗ trợ ra quyết định thực tế.
5. Tài liệu tham khảo
[1] Project: Sales Prediction - Nguyễn Quốc Thái, Hồ Quang Hiển, Đinh Quang Vinh.
Chưa có bình luận nào. Hãy là người đầu tiên!