0 回歸決策樹展示
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import root_mean_squared_error, r2_score
from sklearn.model_selection import GridSearchCV,KFold
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
data =pd.read_csv("../data/house-prices-advanced-regression-techniques/train.csv")
# 去空
# FireplaceQu表示壁爐質量,空值代表沒有壁爐,將空值設置為No Fireplace即可,不必刪除
for i in ["Alley","PoolQC","Fence","MiscVal","MiscFeature","MasVnrType","FireplaceQu","BsmtQual","BsmtCond","BsmtExposure","BsmtFinType1","BsmtFinType2","GarageType","GarageFinish","GarageQual","GarageCond","GarageYrBlt"]:data[i]=data[i].fillna(f"no{i}")
# data.isna().any()
data["LotFrontage"]=data["LotFrontage"].fillna(data["LotFrontage"].mean())
# Electrical還有一個空值,直接刪除
data.dropna(inplace=True)X = data.drop(columns="SalePrice")
y = data["SalePrice"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)transformer = DictVectorizer()
X_train = transformer.fit_transform(X_train.to_dict(orient="records"))
X_test =transformer.transform(X_test.to_dict(orient = "records"))
#
X_train = pd.DataFrame(X_train.toarray(),columns=transformer.get_feature_names_out())
X_test = pd.DataFrame(X_test.toarray(),columns=transformer.get_feature_names_out())
#%%estimator = DecisionTreeRegressor( )
cv = KFold(n_splits=5)
estimator =GridSearchCV(estimator,param_grid={'max_depth': [2,5,10,15,20,30],"min_samples_split":[3,5,7,10,15,20],"min_samples_leaf":[1,3,5,7,10,15,20,30],
},scoring='neg_mean_squared_error',cv=cv,n_jobs=-1)#設負均方誤差為目標estimator.fit(X_train,y_train)print("best_params_",estimator.best_params_)
print("best_score_",estimator.best_score_)
y_pred = estimator.best_estimator_.predict(X_test)
y_pred_train = estimator.best_estimator_.predict(X_train)print(f"Root Mean Squared Error: {root_mean_squared_error(y_test,y_pred)}")# 重要性評估
# 構建特征重要性表
importances = pd.DataFrame({"feature": X_train.columns,"importance": estimator.best_estimator_.feature_importances_
})# 按重要性降序排序
importances = importances.sort_values(by="importance", ascending=False)
print(importances)
1 相關知識
(信息熵和基尼指數的公式都是構造出來的,根據現有的理論用創造一個滿足所有理論因素的公式來描述)
1.1 信息熵
信息熵(Information Entropy)用來衡量信息的不確定性或隨機性程度。
定義
對于一個離散隨機變量 XXX,其可能取值為 {x1,x2,...,xn}\{x_1, x_2, ..., x_n\}{x1?,x2?,...,xn?},對應的概率分布為 {p1,p2,...,pn}\{p_1, p_2, ..., p_n\}{p1?,p2?,...,pn?},則信息熵定義為:
H(X)=?∑i=1npilog?2piH(X) = -\sum_{i=1}^{n} p_i \log_2 p_iH(X)=?i=1∑n?pi?log2?pi?
其中,pi=P(X=xi)p_i = P(X = x_i)pi?=P(X=xi?) 表示隨機變量 XXX 取值為 xix_ixi? 的概率。
物理意義
信息熵反映了系統的不確定性:
- 熵值越大,系統越混亂,不確定性越高
- 熵值越小,系統越有序,不確定性越低
- 當系統完全確定時,熵為0
1.2 條件信息熵
條件信息熵(Conditional Information Entropy)表示在已知隨機變量 YYY 的條件下,隨機變量 XXX 的不確定性。
定義
給定隨機變量 XXX 和 YYY,XXX 在 YYY 條件下的條件熵定義為:
H(X∣Y)=∑jP(Y=yj)H(X∣Y=yj)H(X|Y) = \sum_{j} P(Y = y_j) H(X|Y = y_j)H(X∣Y)=j∑?P(Y=yj?)H(X∣Y=yj?)
=?∑jP(Y=yj)∑iP(X=xi∣Y=yj)log?2P(X=xi∣Y=yj)= -\sum_{j} P(Y = y_j) \sum_{i} P(X = x_i|Y = y_j) \log_2 P(X = x_i|Y = y_j)=?j∑?P(Y=yj?)i∑?P(X=xi?∣Y=yj?)log2?P(X=xi?∣Y=yj?)
=?∑i,jP(X=xi,Y=yj)log?2P(X=xi∣Y=yj)= -\sum_{i,j} P(X = x_i, Y = y_j) \log_2 P(X = x_i|Y = y_j)=?i,j∑?P(X=xi?,Y=yj?)log2?P(X=xi?∣Y=yj?)
1.3 信息增益
信息增益(Information Gain)是機器學習中特征選擇的重要指標,特別是在決策樹算法中廣泛應用。
定義
信息增益定義為原始信息熵與條件信息熵的差值:
IG(X,Y)=H(X)?H(X∣Y)IG(X, Y) = H(X) - H(X|Y)IG(X,Y)=H(X)?H(X∣Y)
也可以表示為:
IG(X,Y)=H(Y)?H(Y∣X)IG(X, Y) = H(Y) - H(Y|X)IG(X,Y)=H(Y)?H(Y∣X)
1.4信息增益比
為了避免信息增益偏向于取值較多的特征,引入信息增益比(Gain Ratio):
GR(X,Y)=IG(X,Y)H(Y)GR(X, Y) = \frac{IG(X, Y)}{H(Y)}GR(X,Y)=H(Y)IG(X,Y)?
信息增益比通過除以特征的固有值來標準化信息增益,使得特征選擇更加公平。
1.5 基尼指數
基尼指數(Gini Index)是另一種衡量數據集純度的指標,廣泛應用于決策樹算法中,特別是CART(Classification and Regression Tree)算法。
定義
對于包含 kkk 個類別的數據集 DDD,基尼指數定義為:
Gini(D)=1?∑i=1kpi2Gini(D) = 1 - \sum_{i=1}^{k} p_i^2Gini(D)=1?∑i=1k?pi2?
其中,pip_ipi? 表示數據集 DDD 中第 iii 類樣本所占的比例。
1.6 條件基尼指數
當根據特征 AAA 將數據集 DDD 劃分為多個子集時,條件基尼指數定義為:
Gini(D,A)=∑v=1V∣Dv∣∣D∣Gini(Dv)Gini(D, A) = \sum_{v=1}^{V} \frac{|D^v|}{|D|} Gini(D^v)Gini(D,A)=∑v=1V?∣D∣∣Dv∣?Gini(Dv)
其中:
- VVV 是特征 AAA 的可能取值數量
- DvD^vDv 表示特征 AAA 取值為 vvv 的樣本子集
- ∣Dv∣|D^v|∣Dv∣ 和 ∣D∣|D|∣D∣ 分別表示子集和原數據集的樣本數量
1.7基尼增益
基尼增益定義為原始基尼指數與條件基尼指數的差值:
Gini_Gain(D,A)=Gini(D)?Gini(D,A)Gini\_Gain(D, A) = Gini(D) - Gini(D, A)Gini_Gain(D,A)=Gini(D)?Gini(D,A)
1.7 基尼指數與信息熵的關系
基尼指數和信息熵都用于衡量數據集的不純度,它們具有相似的性質:
- 兩者都在數據集完全純凈時達到最小值0
- 兩者都在各類樣本均勻分布時達到最大值
- 在二分類問題中:Gini(D)≈2p(1?p)Gini(D) \approx 2p(1-p)Gini(D)≈2p(1?p),H(D)=?plog?2p?(1?p)log?2(1?p)H(D) = -p\log_2 p - (1-p)\log_2(1-p)H(D)=?plog2?p?(1?p)log2?(1?p)
2決策樹
2.1 決策樹
1> 是一種樹形結構,本質是一顆由多個判斷節點組成的樹
2> 其中每個內部節點表示一個屬性上的判斷,
3> 每個分支代表一個判斷結果的輸出,
4> 最后每個葉節點代表一種分類結果。
2.2 決策樹的優化:
決策樹學習旨在構建一個與訓練數據擬合很好,并且復雜度小的決策樹。因為從可能的決策樹中直接選取最優決策樹是NP完全問題(NP完全問題目前無法通過確定性算法直接求解,只能通過啟發式函數(如信息熵、信息增益)逼近解,)。
決策樹學習算法包括3部分:特征選擇、樹的生成和樹的剪枝。常用的算法有ID3、C4.5和CART。
2.3 決策樹特征選擇的準則
1】 樣本集合DDD對特征AAA的信息增益(ID3)
g(D,A)=H(D)?H(D∣A)g(D, A)=H(D)-H(D|A)g(D,A)=H(D)?H(D∣A)
H(D)=?∑k=1K∣Ck∣∣D∣log?2∣Ck∣∣D∣H(D)=-\sum_{k=1}^{K} \frac{\left|C_{k}\right|}{|D|} \log _{2} \frac{\left|C_{k}\right|}{|D|}H(D)=?k=1∑K?∣D∣∣Ck?∣?log2?∣D∣∣Ck?∣?
H(D∣A)=∑i=1n∣Di∣∣D∣H(Di)H(D | A)=\sum_{i=1}^{n} \frac{\left|D_{i}\right|}{|D|} H\left(D_{i}\right)H(D∣A)=i=1∑n?∣D∣∣Di?∣?H(Di?)
其中,H(D)H(D)H(D)是數據集DDD的熵,H(Di)H(D_i)H(Di?)是數據集DiD_iDi?的熵,H(D∣A)H(D|A)H(D∣A)是數據集DDD對特征AAA的條件熵。 DiD_iDi?是DDD中特征AAA取第iii個值的樣本子集,CkC_kCk?是DDD中屬于第kkk類的樣本子集。nnn是特征AAA取 值的個數,KKK是類的個數。
2】 樣本集合DDD對特征AAA的信息增益比(C4.5)
通過計算信息增益率,我們可以確保選擇的特征不僅能提供較大的信息增益,還能避免過于依賴那些取值較多、看似“更復雜”的特征。
gR(D,A)=g(D,A)H(D)g_{R}(D, A)=\frac{g(D, A)}{H(D)}gR?(D,A)=H(D)g(D,A)?
其中,g(D,A)g(D,A)g(D,A)是信息增益,H(D)H(D)H(D)是數據集DDD的熵。
3】 樣本集合DDD的基尼指數(CART)
(相比信息熵的優勢:計算簡單、數值穩定)
Gini?(D)=1?∑k=1K(∣Ck∣∣D∣)2\operatorname{Gini}(D)=1-\sum_{k=1}^{K}\left(\frac{\left|C_{k}\right|}{|D|}\right)^{2}Gini(D)=1?k=1∑K?(∣D∣∣Ck?∣?)2
特征AAA條件下集合DDD的基尼指數:
Gini?(D,A)=∣D1∣∣D∣Gini?(D1)+∣D2∣∣D∣Gini?(D2)\operatorname{Gini}(D, A)=\frac{\left|D_{1}\right|}{|D|} \operatorname{Gini}\left(D_{1}\right)+\frac{\left|D_{2}\right|}{|D|} \operatorname{Gini}\left(D_{2}\right)Gini(D,A)=∣D∣∣D1?∣?Gini(D1?)+∣D∣∣D2?∣?Gini(D2?)
3 決策樹構建
計算y的信息熵(gini指數),然后對每個特征的每個類別進行劃分,比如選類別1,類別1有A/B,計算出選A的概率×A行的信息熵/gini+B的概率何B行的信息熵/gini(這就是劃分后的信息熵/gini),最后算出信息增益、信息增益比或者gini增益,最大的作為第一個決策樹節點,然后若信息熵仍不為0,繼續選擇下一個節點,若為零,則分出一個分支通向分類結果。循環這個過程直到葉子節點的信息熵全為0,皆為分類結果,至此完成決策樹構建。
注意點:
1 對于連續的特征決策樹對連續特征就是“把所有取值排序,檢查每兩個相鄰值的中點,挑一個讓不純度下降最大的作為閾值”, “分位數近似”只檢查若干分位點而非所有兩個相鄰值的中點。
2 由于樹的分裂與否是自己和自己對比,不需要和別的特征交互,故天然不需要同度量化
4 決策樹的剪枝:
由于生成的決策樹存在過擬合問題,需要對它進行剪枝,以簡化學到的決策樹。決策樹的剪枝,往往從已生成的樹上剪掉一些葉結點或葉結點以上的子樹,并將其父結點或根結點作為新的葉結點,從而簡化生成的決策樹。
4.1預剪枝
預剪枝是在構建決策樹時,在節點進行分裂前,根據一些預定義的條件來決定是否繼續分裂。Scikit - learn中提供了一些參數來實現預剪枝:
max_depth:用于設置決策樹的最大深度。如果樹的深度達到或超過此值,節點將不再分裂。
min_samples_split:用于設置進行分裂所需的最小樣本數。如果節點中的樣本數少于此值,節點將不再分裂。
min_samples_leaf:用于設置葉節點中的最小樣本數。如果葉節點中的樣本數少于此值,則不會繼續分裂
4.2 后剪枝
常見的后剪枝標準/方法
1 誤差估計剪枝(Error-based Pruning)
典型代表:C4.5 使用的基于置信區間的錯誤率估計。
思路:用統計方法估計子樹和剪枝后葉子節點的分類誤差,剪掉對泛化誤差無益的子樹。
利用二項分布的置信區間計算誤差上界。
2 代價復雜度剪枝(Cost-Complexity Pruning)
典型代表:CART 算法采用的剪枝方式。
公式:
Rα(T)=R(T)+α∣T∣R_α(T) = R(T) + α |T|Rα?(T)=R(T)+α∣T∣
其中 R(T) 是樹 T 的誤差率,|T| 是葉節點數,α 是復雜度懲罰系數。
通過調整 α 權衡樹的復雜度和誤差,選擇最優子樹。
一般使用交叉驗證選擇 α。
3 最小誤差剪枝(Minimal Error Pruning)
直接比較剪枝前后在驗證集上的誤差率。
如果剪枝后誤差不增大,則進行剪枝。
4 統計檢驗剪枝
用統計檢驗(如卡方檢驗)判斷節點分裂是否顯著,不顯著則剪枝。
5 ID3、C4.5、CART算法的差別
對比維度 | ID3 | C4.5 | CART | 改進意義 |
---|---|---|---|---|
特征選擇指標 | 信息增益(Information Gain) | 信息增益率(Gain Ratio) | 分類:基尼指數(Gini Index) 回歸:最小平方誤差(MSE) | 解決 ID3 偏向取值多特征(比如極端情況特征分類為一行一類,那每一類都是純的,但是分類沒有意義)的問題,CART 則統一了分類和回歸的處理方式 |
特征類型支持 | 僅支持離散特征 | 支持離散特征和連續特征 | 支持離散特征和連續特征 | 擴展到數值型特征,提高算法適用性 |
缺失值處理 | 不支持 | 支持(概率權重分配樣本到分支) | 支持(替代變量或加權處理) | 減少因缺失值導致的數據丟失 |
樹結構 | 多叉樹 | 多叉樹 | 二叉樹 | CART 的二叉劃分便于剪枝和計算 |
剪枝策略 | 無剪枝(易過擬合) | 后剪枝(基于置信區間錯誤率) | 代價復雜度剪枝(Cost-Complexity Pruning) | 提高泛化能力,減少過擬合 |
輸出結果 | 類別標簽 | 類別標簽或類別概率分布 | 分類標簽/概率 或 回歸預測值 | 輸出概率/連續值提升靈活性 |
對噪聲和異常值的魯棒性 | 較差 | 較好 | 較好 | 剪枝和連續值處理提升了抗噪性 |
適用任務 | 分類 | 分類 | 分類 + 回歸 | CART 能用于回歸,應用范圍更廣 |
泛化能力 | 較弱 | 較強 | 較強 | 改進后模型更適應新數據 |
6 決策樹算法api
class sklearn.tree.DecisionTreeClassifier(criterion=“gini”,
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
random_state=None)
參數:
1】criterion:特征選擇標準
“gini”
或者
“entropy”,前者代表基尼系數,后者代表信息增益。?默認
“gini”,即CART算法。
2】min_samples_split:內部節點再劃分所需最?樣本數
這個值限制了?樹繼續劃分的條件,如果某節點的樣本數少于min_samples_split,
則不會繼續再嘗試選擇最優特征來進?劃分。
默認是2.如果樣本量不?,不需要管這個值。
如果樣本量數量級?常?,則推薦增?這個值。
?個項?例?,有?概10萬樣本,建?決策樹時,選擇了min_samples_split = 10。
可以作為參考。
3】min_samples_leaf:葉?節點最少樣本數
這個值限制了葉?節點最少的樣本數,如果某葉?節點數??于樣本數,
則會和兄弟節點?起被剪枝。
默認是1, 可以輸?最少的樣本數的整數,或者最少樣本數占樣本總數的百分?。
如果樣本量不?,不需要管這個值。如果樣本量數量級?常?,則推薦增?這個值。
之前的10萬樣本項?使?min_samples_leaf的值為5,僅供參考。
4】max_depth:決策樹最?深度
決策樹的最?深度,默認可以不輸?
如果不輸?的話,決策樹在建??樹的時候不會限制?樹的深度。
?般來說,數據少或者特征少的時候可以不管這個值。
如果模型樣本量多,特征也多的情況下,推薦限制這個最?深度,具體的取值取決于數據的分布。
常?的可以取值10 - 100
之間
5】random_state:隨機數種?
6.1 決策樹分類
from sklearn.tree import DecisionTreeClassifier
import pandas as pd
data = pd.read_csv('../pandasPD/data/titanic/train.csv')
X = data[["Sex", "Age", "Sex"]]
y = data["Survived"]
X.loc[:, "Age"] = X.loc[:, "Age"].fillna(X.loc[:, "Age"].median()) # 去空
#%%
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
#%%
from sklearn.feature_extraction import DictVectorizer
transfer = DictVectorizer()
X_train = transfer.fit_transform(X_train.to_dict(orient='records')) # orient='records'將每一行數據轉換成一個字典
X_test = transfer.transform(X_test.to_dict(orient='records')) # orient='records'將每一行數據轉換成一個字典
# 查看結果
pd.DataFrame(X_train.toarray(), columns=transfer.get_feature_names_out())
# 不需要特征縮放
#%%
# 訓練
estimator = DecisionTreeClassifier(# max_depth=5
)
estimator.fit(X_train, y_train)
#%%
from sklearn.metrics import accuracy_score, recall_score, f1_score, classification_report
# 評估
y_pred = estimator.predict(X_test)
ret = estimator.score(X_test, y_test)
print(f"準確率:{ret}")
print(f"精確度:{accuracy_score(y_test, y_pred)}")
6.2 回歸決策樹
關鍵特點:
- 可解釋性強:決策路徑像流程圖一樣清晰
- 自動特征選擇:會優先用最有區分度的特征(比如先問犬種再問年齡)
- 不需要特征縮放:對身高(cm)和體重(kg)這種混合單位很友好
注意:
- 容易過擬合(解決方法:限制樹深度/設置最小樣本量)
- 對異常值敏感(比如遇到200斤的超級胖柯基)
- 預測值是階梯狀的(無法輸出連續曲線)
葉節點(Leaf Node)
回歸樹中的葉節點表示最終的預測區域,每個葉節點對應訓練數據的一個子集。葉節點的預測值為該節點中所有訓練樣本目標值的均值。
(換句話說就是每個訓練樣本最后都會進入某個葉子節點,這個葉子節點的值就取決于那些進入這個葉子節點的樣本的平均值)
純度指標(Purity Measure)
回歸樹通過最小化葉節點內目標值的**均方誤差(MSE)**來衡量純度,分裂時選擇使得加權子節點MSE和最小的特征及閾值。
import numpy as np
from sklearn.tree import DecisionTreeRegressor,plot_tree
from sklearn.metrics import root_mean_squared_error, r2_score
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
# 假如有7天的銷售數據 特征:
# 天氣溫度
# 是否周末(1是 0否)
# 附件的活動人數# 標簽(目標):
# 賣出的冰淇淋 (箱)
new_data = [[28,0,3,42],[32,1,5,60],[25,0,2,38],[30,1,4,55],[22,0,1,25],[35,1,6,70],[26,0,2,33]]
new_data = np.array(new_data)
X =new_data[:,:3]
y = new_data[:,3]
estimator = DecisionTreeRegressor(max_depth=2,# 樹的最大深度min_samples_split=2 , # 節點至少需要兩個樣本才能分裂min_samples_leaf=1,random_state=42,
)
estimator.fit(X,y)
y_pred = estimator.predict(X)
print(root_mean_squared_error(y,y_pred))
plt.figure(figsize=(10,8))
plot_tree(estimator,feature_names=["溫度","周末","活動人數"],filled=True, # 填充顏色 )
plt.show()
new_x = np.array([30,0,5]).reshape(1,-1)
pred=estimator.predict(new_x)
print(pred)
可視化結果