Tóm tắt về Ensemble Learning: Bagging / Boosting/ Stacking(1)

# 1. Ensemble Learning là gì
Mục tiêu trong học máy là xây dựng các máy học có tính tổng quát hóa cao từ dữ liệu. Có một số cách để cải thiện tính tổng quát hóa, nhưng có hai chính sách sau đây:
- Cải thiện hiệu suất của một máy học (model).
- Chuẩn bị nhiều máy học (model) và tổng hợp kết quả dự đoán của chúng để nâng cao tính tổng quát hóa.

Phương pháp thứ hai được gọi là Ensemble Learning. Sử dụng nhiều máy học (model) để đưa ra độ chính xác cao của mô hình máy học.

## 1.1. Tại sao Ensemble Learning lại có hiệu quả
· Là một phương pháp Ensemble Learning, nó có thể chỉ đơn giản là một cuộc bỏ phiếu đa số cho những máy học yếu (弱学習器).
· Trong bài toán phân biệt nhị phân (0 hoặc 1), nếu trên (m + 1) / 2 số máy học yếu (弱学習器) đưa ra phán đoán sai lầm, phán đoán cuối cùng sẽ bị sai sót bởi đa số phiếu.
· Nếu mỗi một máy học yếu (弱学習器) được thống kê độc lập và xác suất lỗi của mỗi máy học yếu là đồng nhất, thì khi chúng ta xem xét xác suất để hơn một nửa số máy học phân loại(分類機) của những máy học yếu(m個の弱学習機の内) phân loại sai, Xác suất trở nên rất nhỏ.

## 1.2. Để làm cho Ensemble Learning hiệu quả hơn
Lưu ý thực hiện các điểm dưới đây, sẽ có thể giúp tăng độ chính xác hơn.
- Sử dụng các máy học yếu khác nhau nhất có thể
- Học từng máy học yếu bằng cách sử dụng các bộ dữ liệu khác nhau nhất có thể. 
Nói cách khác, các máy học yếu càng độc lập với nhau, thì hiệu quả của Ensemble Learning sẽ càng tốt.

## 1.3. Phân loại Ensemble Learning
Một cách đại khải, Ensemble Learning được chia thành 3 loại sau đây.
- Bagging (đóng bao)
- Boosting (tăng cường)
- Stacking (Xếp chồng)
Chúng tôi sẽ mô tả từng phương pháp và các chủ đề liên quan dưới đây. (Bổ sung sau)

# 2. Bagging (đóng bao)
https://www.st-hakky-blog.com/entry/2017/08/07/162938

# 3. Boosting (tăng cường)
https://www.st-hakky-blog.com/entry/2017/08/07/163216

# 4. Stacking (Xếp chồng)
Stacking (Xếp chồng) có nghĩa là, như tên gọi của nó, các mô hình được xếp chồng lên nhau.

## 4.1. Tổng quan
Tôi sẽ giải thích ngắn gọn các phác thảo dưới đây. Đầu tiên, chúng ta tách tập dữ liệu train thành nhiều phần và cho train với cái máy học(model) khác nhau như hình dưới.
![1.jpg](https://qiita-image-store.s3.amazonaws.com/0/324823/db606fad-f2cc-b5a5-fb99-94520743cd8a.jpeg)
Trích dẫn: Géron, Aurélien. "Hands on Machine Learning with scikit-learn and Tensorflow." (2017).

Sau đó, chúng ta sử dụng các máy học (trained) để dự đoán và thu được giá trị với tập dữ liệu được sử dụng để train (xem hình bên dưới). Chúng ta sẽ sử dụng những giá trị dự đoán này làm "features mới " để phát triển thêm một máy học mới. Đây là xếp chồng.

![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/324823/d06b2491-10a8-e5eb-795e-35a166395d0c.jpeg)
Trích dẫn: Géron, Aurélien. "Hands on Machine Learning with scikit-learn and Tensorflow." (2017).

Trong hình trên chỉ có một ngăn xếp được thực hiện, nhưng tất nhiên cũng có thể xếp chồng nhiều lớp như sau.
![3.jpg](https://qiita-image-store.s3.amazonaws.com/0/324823/9d268c75-6eeb-38c6-3ff5-f397fe47c99d.jpeg)

## 4.2. Code thử bằng Python
Dataset: https://www.kaggle.com/c/house-prices-advanced-regression-techniques

```python
import numpy as np
import pandas as pd 

from sklearn.linear_model import LinearRegression
from sklearn.neighbors import KNeighborsRegressor
from lightgbm import LGBMRegressor

from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Load dataset
train = pd.read_csv('../dataset/house-prices/train.csv')
test = pd.read_csv('../dataset/house-prices/test.csv')
train.shape #(1460, 81)
test.shape #(1459, 80)


# Preprocess
nrow_train = train.shape[0]

merge = pd.concat([train, test], sort=False)
merge.shape #(2919, 81)

dummies = pd.get_dummies(merge.select_dtypes(include=['object']))
merge = pd.concat([merge, dummies], axis=1)

df_train = merge[:nrow_train]
df_test = merge[nrow_train:]

X = df_train.drop(['SalePrice'], axis=1).select_dtypes(exclude=['object']).fillna(0)
y = np.log(df_train['SalePrice'].fillna(0))

#df_test = df_test.drop(['SalePrice'], axis=1).select_dtypes(exclude=['object']).fillna(0)


#Split train/valid/test
random_state = 1021
X_train_valid, X_meta_valid, y_train_valid, y_meta_valid = 
                             train_test_split(X, y, test_size=0.2, random_state=random_state)
#X_train_valid: 0.8 X
#y_train_valid: 0.8 y
#X_meta_valid: 0.2 X
#y_meta_valid: 0.2 y

X_train, X_valid, y_train, y_valid = 
      train_test_split(X_train_valid, y_train_valid, test_size=0.5, random_state=random_state)
#X_train: 0.5 X_train_valid
#y_train: 0.5 y_train_valid
#X_valid: 0.5 X_train_valid
#y_valid: 0.5 y_train_valid

# Stacking
# train base model
base_model_1 = LinearRegression()
base_model_2 = LGBMRegressor()
base_model_3 = KNeighborsRegressor()

base_model_1.fit(X_train, y_train)
base_model_2.fit(X_train, y_train)
base_model_3.fit(X_train, y_train)

# base predicts
base_pred_1 = base_model_1.predict(X_valid)
base_pred_2 = base_model_2.predict(X_valid)
base_pred_3 = base_model_3.predict(X_valid)

# test predicts for final result 
valid_pred_1 = base_model_1.predict(X_meta_valid)
valid_pred_2 = base_model_2.predict(X_meta_valid)
valid_pred_3 = base_model_3.predict(X_meta_valid)

print ("mean squared error of model 1: {:.4f}".format(mean_squared_error(y_meta_valid, valid_pred_1)) )
print ("mean squared error of model 2: {:.4f}".format(mean_squared_error(y_meta_valid, valid_pred_2)) )
print ("mean squared error of model 3: {:.4f}".format(mean_squared_error(y_meta_valid, valid_pred_3)) )

#mean squared error of model 1: 0.0239
#mean squared error of model 2: 0.0181
#mean squared error of model 3: 0.0634

# stack base predicts for training meta model
stacked_predictions = np.column_stack((base_pred_1, base_pred_2, base_pred_3))

# stack test predicts for final result 
stacked_valid_predictions = np.column_stack((valid_pred_1, valid_pred_2, valid_pred_3))

# train meta model 
meta_model = LinearRegression()
meta_model.fit(stacked_predictions, y_valid)

# final result 
meta_valid_pred = meta_model.predict(stacked_valid_predictions)
print ("mean squared error of meta model: {:.4f}".format(mean_squared_error(y_meta_valid, meta_valid_pred)) )

#mean squared error of meta model: 0.0175

```

# 5. Link bài viết tham khảo
https://www.st-hakky-blog.com/entry/2017/07/28/214518

Bài viết liên quan:
https://forum.machinelearningcoban.com/t/feature-engineering-stacking-va-ensemble-cho-cuoc-thi-phan-loai-sac-thai-binh-luan/4298
https://github.com/ngxbac/aivivn_phanloaisacthaibinhluan/blob/master/stacking.ipynb

***Heamy***
[heamy - walkthrough.ipynb](https://github.com/rushter/heamy/blob/master/examples/walkthrough.ipynb)
[Using heamy in a project](https://heamy.readthedocs.io/en/latest/usage.html#stacking)
[Kaggleでよく使われるStacking/Blendingをheamy、Stacknetをpystacknetで高速に実装する](https://gist.github.com/ikedaosushi/a30e28c9abe6e353ba3866fac43b2708)
[repo](https://blog.ikedaosushi.com/entry/2018/12/15/212508)