# **【Kaggle - Intro to Machine Learning 機器學習入門_Decision Tree/Random Forest Regression】**
:::info
- How Models Work 什麼是模型?
- 什麼是 Decision Tree 決策樹?
- Basic Data Exploration 資料探索
- Your First Machine Learning Model 模型訓練
- Model Validation 模型驗證
- Underfitting and Overfitting 欠擬合和過擬合
- 什麼是 Random Forest Regressoion 隨機森林?
:::
Source [Kaggle](https://www.kaggle.com/learn/intro-to-machine-learning)

## 什麼是模型?
假設我想知道一個地區的房地產價值,應該如何做?多數人可能會依據實價登錄、過去經驗,比如同樣大小、同樣地段的房子,過去賣多少錢來判斷
在機器學習中,「模型」就像判斷,從大量的歷史數據中學習規律(地段、屋齡、樓層、坪數、房間數、大樓/華廈/公寓、與車站/學校距離等),再根據這些規律對新的數據進行預測
學習的過程,稱為「擬合(fitting)」或「訓練(training)」模型,訓練模型的數據,就叫做「訓練數據(training data)」
Kaggle這門課用【 決策樹 Learning_Decision Tree 】
<br/>
## 什麼是 Decesion Tree 決策樹?
想像一下我們在玩一個「10個問題」的遊戲,要回答一系列的問題,回答A走左邊、B走右邊,每個問題的答案都會引導我們走向下一個問題,直到得出一個結果
[網路圖片](https://www.smartdraw.com/decision-tree/)

```
根節點 (Root Node):樹的最頂端,是所有數據的起始點,提出第一個問題來分割數據
分支 (Branches):從每個節點延伸出來的線條,代表著問題的不同答案或不同結果
內部節點 (Internal Node):根節點以下的分支點,每個內部節點都代表一個「決策點」或「問題」
葉子節點 (Leaf Node):也稱為「終端節點」,當數據到達一個葉子節點時,就表示已經得出最終的分類結果或預測值
```
當我們有一個新房子要估價時,會讓它從決策樹的根節點開始,根據特徵回答每個節點的問題
1. 是否有兩間房間?不是的話走左邊,是的話走右邊
2. (走左邊) 是否大於8500平方公尺?不是的話走左邊,到達結果146k,是的話走右邊,到達結果188k
4. (走右邊) 是否大於11500平方公尺?不是的話走左邊,到達結果170k,是的話走右邊,到達結果233k

<br/>
## Basic Data Exploration 資料探索
使用的資料集
[Melbourne Housing Snapshot](https://www.kaggle.com/datasets/dansbecker/melbourne-housing-snapshot)

查看數據型態
```=
melbourne_data.info
```

所有特徵
```=
melbourne_data.columns
```

```=
for c in melbourne_data_ori.columns:
print(c, ":", melbourne_data_ori[c].value_counts(dropna=False))
print()
```

```=
'Suburb':郊區或地區名稱,類別型 (Categorical)
'Address': 地址,文本型 (Textual)
'Rooms':房間數量,數值型 (Numerical)
'Type':房屋類型,h:House (獨立屋)、u:Unit (公寓/單元房)、t:Townhouse (聯排別墅),類別型 (Categorical)
'Price':價格,數值型 (Numerical)
'Method:銷售方式,S:Sold (已售出)、SA:Subject to Authority (待房東確認)、PI:Passed in (流拍)、VB:Vendor Bid (賣家出價,常見於拍賣)、SP:Sold Prior (預售),類別型 (Categorical)
'SellerG':賣家代理公司,類別型 (Categorical)
'Date':房屋售出日期,日期型 (Date)
'Distance':到市中心距離,數值型 (Numerical)
'Postcode':郵遞區號,數值型 (Numerical)
'Bedroom2':房間數,數值型 (Numerical)
'Bathroom':浴室數,數值型 (Numerical)
'Car':車位數,數值型 (Numerical)
'Landsize':土地面積,數值型 (Numerical)
'BuildingArea':建築面積,數值型 (Numerical)
'YearBuilt':建造年份,類別型 (Categorical)
'CouncilArea':所屬市議會,類別型 (Categorical)
'Lattitude':緯度,數值型 (Numerical)
'Longtitude':經度,數值型 (Numerical)
'Regionname':區域名稱,類別型 (Categorical)
'Propertycount':物業數量,數值型 (Numerical)
```
處理缺失值,這裡用最簡單的方法,直接丟棄
實務上可能會以某群的平均值、補0等來處理

<br/>
## Your First Machine Learning Model 模型訓練
先設Y值,也就是分類結果/預測值
```=
y = melbourne_data.Price
```
再設X值,也就是要拿去訓練的特徵
```=
melbourne_features = ['Rooms', 'Bathroom', 'Landsize', 'Lattitude', 'Longtitude']
X = melbourne_data[melbourne_features]
```
model
```=
# model
from sklearn.tree import DecisionTreeRegressor
melbourne_model = DecisionTreeRegressor(random_state=1)
melbourne_model.fit(X, y)
```
```=
print("Making predictions for the following 5 houses:")
print(X.head())
print("The predictions are")
print(melbourne_model.predict(X.head()))
```

<br/>
## Model Validation 模型驗證
前面的模型會有問題,當我們把資料拿去訓練後,又把資料拿來測試,不就不準了嗎? (誤差為0)

因此我們要把資料切成訓練集和驗證集
訓練集用來訓練
驗證集用來預測
預測出來的結果,再和真實的結果比較,算出誤差和準確率
```=
from sklearn.model_selection import train_test_split
train_X, val_X, train_y, val_y = train_test_split(X, y, random_state = 0)
#
melbourne_model = DecisionTreeRegressor()
melbourne_model.fit(train_X, train_y)
# 預測訓練集和驗證集
train_predictions = melbourne_model.predict(train_X)
val_predictions = melbourne_model.predict(val_X)
# MAE
train_mae = mean_absolute_error(train_y, train_predictions)
val_mae = mean_absolute_error(val_y, val_predictions)
print(f"MAE 訓練誤差: {train_mae:.2f}")
print(f"MAE 驗證誤差: {val_mae:.2f}")
```

<br/>
## Underfitting and Overfitting 欠擬合和過擬合
Underfitting(欠擬合):
模型太簡單,無法學到訓練資料中的結構 → 訓練誤差和驗證誤差都很高
Overfitting(過擬合):
模型太複雜,學會了訓練資料的雜訊(noise) → 訓練誤差非常小,但驗證誤差很高
我們前面的模型是過擬合,因此我們可以限制葉子節點數量,預設是 None
[DecisionTreeRegressor](https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeRegressor.html)
用 max_leaf_nodes(葉節點數量)來控制模型複雜度
max_leaf_nodes 小 → 模型限制多,學不夠 → 容易欠擬合
max_leaf_nodes 大 → 模型自由度高,學得太多 → 容易過擬合
```=
from sklearn.metrics import mean_absolute_error
from sklearn.tree import DecisionTreeRegressor
def get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y):
model = DecisionTreeRegressor(max_leaf_nodes=max_leaf_nodes, random_state=0)
model.fit(train_X, train_y)
#
preds_train = model.predict(train_X)
preds_val = model.predict(val_X)
#
train_mae = mean_absolute_error(train_y, preds_train)
val_mae = mean_absolute_error(val_y, preds_val)
return train_mae, val_mae
```
```=
for max_leaf_nodes in [5, 50, 500, 5000]:
train_mae, val_mae = get_mae(max_leaf_nodes, train_X, val_X, train_y, val_y)
print(f"Max leaf nodes: {max_leaf_nodes:<5} \t訓練 MAE: {train_mae:.2f} \t驗證 MAE: {val_mae:.2f}")
```

5: 欠擬合(模型太簡單)
50: 稍好一些,但仍欠擬合
500: 模型能力增強,開始貼近資料結構
5000: 過擬合,訓練超好,但泛化差
<br/>
## 什麼是 Random Forest Regression 隨機森林?
這裡我們試著改用 RandomForestRegressor
Random Forest Regressoion 是一種 集成學習(Ensemble Learning) 的方法,屬於 隨機森林(Random Forest) 演算法的迴歸版本
結合多棵決策樹,每棵樹都是在不同的隨機資料上訓練出來的
怎麼運作的?
1. 資料隨機抽樣(Bagging)
使用 Bootstrap 抽樣法:從訓練資料中「有放回地隨機抽樣」,每份大小與原資料相同,但資料點可能重複,每份子樣本訓練成一棵 Decision Tree
假設1000筆訓練資料,抽一筆後 -> 放回 -> 再抽一筆...循環1000次
2. 特徵隨機選擇(Feature Randomness)
在每個節點分裂時,隨機挑選一部分特徵來考慮,而不是使用全部特徵,這會讓每棵樹看起來都不太一樣,增加多樣性,也降低了過擬合的風險
```=
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
forest_model = RandomForestRegressor(random_state=1)
forest_model.fit(train_X, train_y)
#
train_preds = forest_model.predict(train_X)
melb_preds = forest_model.predict(val_X)
train_mae = mean_absolute_error(train_y, train_preds)
val_mae = mean_absolute_error(val_y, melb_preds)
print(f"MAE 訓練誤差: {train_mae:.2f}")
print(f"MAE 驗證誤差: {val_mae:.2f}")
```

雖然比起決策樹,隨機森林訓練誤差不是最低的,但MAE,也就是泛化誤差更小