首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【机器学习】决策树回归与集成算法

  • 25-02-16 04:40
  • 2124
  • 11997
blog.csdn.net

文章目录

  • 介绍
    • 决策树回归
    • 关键点
    • 集成算法
    • 注意事项:
    • 决策树回归与集成算法的结合
  • 1、决策回归树原理概述
  • 2、决策回归树算例
    • 2.1、决策树预测圆的轨迹
    • 2.2、增加决策树深度
    • 2.3、决策回归树分裂原理剖析
  • 3、决策回归树 VS 线性回归
  • 4、集成算法
    • 4.1、集成算法概述
    • 4.2、构造不同模型(朋友)
    • 4.3、集成算法不同方式
    • 4.4、Bagging集成算法步骤
  • 5、随机森林
    • 5.1、随机森林介绍
    • 5.2、随机森林实战
    • 5.3、随机森林可视化
    • 5.4、随机森林总结
  • 6、极限森林
    • 6.1、极限森林介绍
    • 6.2、极限森林实战

介绍

决策树回归(Decision Tree Regression)和集成算法(Ensemble Algorithms)是机器学习中用于解决回归问题的两种重要方法。下面将分别介绍这两种技术,并探讨它们如何结合使用以提升预测性能。

决策树回归

决策树回归是一种非参数化的监督学习方法,它通过构建一棵或多棵树来对连续值的目标变量进行预测。与分类决策树不同的是,回归决策树的叶节点保存的是一个连续数值而非类别标签。在训练过程中,决策树尝试找到最佳分割点,使得每个子集内部的目标变量值尽可能相同,从而最小化损失函数(如均方误差MSE)。

关键点

  • 分割标准:通常使用均方误差(Mean Squared Error, MSE)或平均绝对误差(Mean Absolute Error, MAE)作为评估指标。
  • 剪枝:为了防止过拟合,可以通过预剪枝或后剪枝的方法来简化模型。
  • 处理缺失值:一些实现可以处理含有缺失值的数据,采用替代分裂或其他策略。

集成算法

集成算法通过组合多个弱学习器(通常是决策树)来形成一个更强的学习器,以提高预测精度、稳定性和泛化能力。以下是几种常见的集成算法:

  1. 随机森林(Random Forest)
    随机森林是由许多决策树组成的集合模型,每棵树都在数据的不同子样本上训练,并且在选择分割属性时也会引入随机性。对于回归任务,随机森林的预测结果是所有树预测值的平均。
  • 优点:
    • 提高了单棵决策树的稳定性,减少了过拟合的风险。
    • 可以处理大量的输入特征,并自动进行特征选择。
    • 能够估算缺失数据的重要性,并提供内部无偏估计误差。
  1. 梯度提升树(Gradient Boosting Trees, GBT)
    梯度提升树是一种迭代式的集成方法,它逐个添加新的树到模型中,每一棵新树都试图纠正前一棵树的错误。具体来说,GBT通过优化一个可微分的损失函数来进行训练,每次迭代都会根据负梯度方向调整权重。
  • 优点:
    • 对异常值有较好的鲁棒性。
    • 在某些情况下比随机森林表现更好,尤其是当数据中有较多的相关特征时。
    • 支持多种损失函数,适用于不同的回归任务。
  1. AdaBoost (Adaptive Boosting)
    AdaBoost也是一种提升方法,但它更侧重于调整训练样本的权重分布。初始时所有样本权重相等,随着训练的进行,那些被误分类的样本会被赋予更高的权重,以便后续的弱学习器更加关注这些“困难”样本。

注意事项:

  • 虽然最初设计用于分类问题,但也可以应用于回归。
  • 相较于GBDT,AdaBoost可能更容易受到噪声和异常值的影响。

决策树回归与集成算法的结合

当单独使用决策树回归时,可能会遇到过拟合的问题,尤其是在树长得非常深的情况下。而集成算法通过组合多个决策树,可以在很大程度上缓解这个问题。例如,随机森林通过多数表决(对于分类)或平均(对于回归)的方式聚合多棵树的结果,不仅提高了准确性,还增强了模型的稳定性。同样地,梯度提升树通过逐步改进模型,也能够显著改善单一决策树的表现。

总之,将决策树回归与集成算法结合起来,可以充分利用两者的优势,得到更为强大和稳定的预测模型。这在实际应用中是非常普遍的做法,特别是在需要处理复杂、高维数据集的情况下。

1、决策回归树原理概述

  • 与分类树一样

  • 裂分指标,使用的是MSE、MAE

    image.png

  • 决策回归树,认为它是分类问题,只是,分的类别多一些!!!

  • 只要树,分类回归,其实就是分类多和少的问题

image.png

2、决策回归树算例

2.1、决策树预测圆的轨迹

导包并创建数据与可视化

import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn import tree
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
import graphviz
X = np.linspace(0,2*np.pi,40).reshape(-1,1)
X_test = np.linspace(0,2*np.pi,187).reshape(-1,1)
# y 一个正弦波,余弦波,圆
y = np.c_[np.sin(X),np.cos(X)]
plt.figure(figsize=(3,3))
plt.scatter(y[:,0],y[:,1])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

使用线性回归预测,看效果

linear = LinearRegression()
linear.fit(X,y) #将数据交给算法,学习,希望算法,找到规律
# X ----> y 是一个圆;预测X_test返回值y_ 如果预测好,也是圆
y_ = linear.predict(X_test)
plt.figure(figsize=(3,3))
plt.scatter(y_[:,0],y_[:,1])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

image.png

使用决策树回归,看效果

model = DecisionTreeRegressor(criterion='mse',max_depth=3)
model.fit(X,y)#X 是40个点 y是一个圆
y_ = model.predict(X_test) #X_test是187点,预测y_应该是一个圆
# 请问y_中有多少数据???
print(y_.shape)
plt.figure(figsize=(6,6))
plt.scatter(y_[:,0],y_[:,1],color = 'green')
plt.savefig('./3-决策树回归效果.png',dpi = 200)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

image.png

思考一下为什么画出来的图形是八个点?

决策回归树可视化

# 决策树形状
dot_data = tree.export_graphviz(model,filled=True)
graph = graphviz.Source(dot_data)
graph.render('./1-决策回归树')
  • 1
  • 2
  • 3
  • 4

image.png

因为决策树深度是3,所以最终得到8个叶节点,所以分成8类!

2.2、增加决策树深度

model = DecisionTreeRegressor(criterion='mse',max_depth=4)
model.fit(X,y)#X 是40个点 y是一个圆
y_ = model.predict(X_test) #X_test是187点,预测y_应该是一个圆
# 请问y_中有多少数据???
print(y_.shape)
plt.figure(figsize=(6,6))
plt.scatter(y_[:,0],y_[:,1],color = 'green')
plt.savefig('./4-增加深度决策树回归效果.png',dpi = 200)
# 决策树形状
dot_data = tree.export_graphviz(model,filled=True)
graph = graphviz.Source(dot_data)
graph.render('./5-增加深度决策回归树')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

image.png

image.png

2.3、决策回归树分裂原理剖析

以上面深度为3的决策树为例

image.png

1、计算未分裂时,整体MSE:

MSE ( y , y ^ ) = 1 n samples ∑ i = 0 n samples − 1 ( y i − y ^ i ) 2 \text{MSE}(y, \hat{y}) = \frac{1}{n_\text{samples}} \sum\limits_{i=0}^{n_\text{samples} - 1} (y_i - \hat{y}_i)^2 MSE(y,y^​)=nsamples​1​i=0∑nsamples​−1​(yi​−y^​i​)2

mse = ((y - y.mean(axis = 0))**2).mean()
print('未分裂时,整体MSE:',mse)
  • 1
  • 2

2、根据分裂标准X[0] <= 3.142,计算分裂后的MSE:

cond = X <= 3.142
part1 = y[cond.reshape(-1)]
part2 = y[(~cond).reshape(-1)]
mse1 = ((part1 - part1.mean(axis = 0))**2).mean()
mse2 = ((part2 - part2.mean(axis = 0))**2).mean()
print(mse1,mse2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3、寻找最佳分裂条件:

split_result = {}
mse_lower = 0.5
for i in range(len(X) - 1):
    split = round(X[i:i + 2].mean(),3)
    cond = X <= split
    part1 = y[cond.reshape(-1)]
    part2 = y[(~cond).reshape(-1)]
    mse1 = ((part1 - part1.mean(axis = 0))**2).mean()
    mse2 = ((part2 - part2.mean(axis = 0))**2).mean()
    mse = mse1 * len(part1)/cond.size + mse2 * len(part2)/cond.size
    mse_result.append(mse)
    if mse < mse_lower:
        split_result.clear()
        split_result[split] = [i,mse]
        mse_lower = mse
print('最佳分裂条件:',split_result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

根据打印输出,我们知道最佳裂分,索引是:19。分裂条件是:3.142。

结论:和直接使用决策回归树绘图显示的结果一模一样~

3、决策回归树 VS 线性回归

1、加载数据

import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn import tree
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
diabetes = datasets.load_diabetes()#糖尿病
X = diabetes['data']
y = diabetes['target']
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 911)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

2、线性回归表现

linear = LinearRegression()
linear.fit(X_train,y_train)
linear.score(X_test,y_test)
  • 1
  • 2
  • 3

3、决策树回归表现

import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'STKaiti'
max_depth = np.arange(1,16)
score = []
for d in max_depth:
    model = DecisionTreeRegressor(max_depth = d)
    model.fit(X_train,y_train)
    score.append(model.score(X_test,y_test))
plt.plot(max_depth,score,'ro-')
plt.xlabel('max_depth',fontsize = 18)
plt.ylabel('Score',fontsize = 18)
plt.title('决策树准确率随着深度变化',pad = 20,fontsize = 20)
plt.savefig('./6-决策树回归糖尿病.png',dpi = 200)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

image.png

4、结论:

  • 对于这个案例,线性回归效果更好一些
  • 糖尿病这个数据,更适合使用方程对规律进行拟合
  • 在很多方面,决策树回归表现也优秀~

4、集成算法

4.1、集成算法概述

image.png

集成算法核心:

少数服从多数,人多力量大,三个臭皮匠顶个诸葛亮。

假设你有 100 个朋友给你出主意投资股票,你怎么做最终的决定?

  1. 选择最牛 x 的一个朋友的意见当作自己的意见(找到最好的单颗决策树)
  2. 所有朋友的意见投票,少数服从多数(随机森林)
  3. 还是牛一点的朋友多给几票,弱鸡一点的少给几票(Adaboost)

聚合模型:

所有朋友的意见投票, 少数服从多数(随机森林对应原理公式)

  • $G(x) = \frac{1}{n}\sum\limits_{i =1}^n1 \times g_i(x) $

牛一点的朋友多给几票,弱鸡一点的少给几票(Adaboost对应原理公式)

  • G ( x ) = 1 n ∑ i = 1 n α i × g i ( x ) ; α i ≥ 0 G(x) = \frac{1}{n}\sum\limits_{i =1}^n \alpha_i \times g_i(x) ;\alpha_i \ge 0 G(x)=n1​i=1∑n​αi​×gi​(x);αi​≥0

4.2、构造不同模型(朋友)

同样的数据,行列都相同,不同的超参数,可以得到不同的模型。

同样的超参数,行相同,列不同,可以得到不同的模型。

同样的超参数,行不同,列相同,可以得到不同的模型。

同样的超参数,同样的数据,但是数据权重不同,可以得到不同的模型。

4.3、集成算法不同方式

  • 方式一Bagging(套袋法)

    • 对训练集进行抽样, 将抽样的结果用于训练 g(x)。
    • 并行,独立训练。
    • 随机森林random forest便是这一类别的代表。
  • 方式二Boosting(提升法)

    • 利用训练集训练出模型,根据本次模型的预测结果,调整训练集。
    • 然后利用调整后的训练集训练下一个模型。
    • 串行,需要第一个模型。
    • Adaboost,GBDT,Xgboost都是提升树算法典型代表。

4.4、Bagging集成算法步骤

  1. Bootstrap(独立自主) : 有放回地对原始数据集进行均匀抽样
  2. 利用每次抽样生成的数据集训练模型
  3. 最终的模型为每次生成的模型进行投票
  4. 其实 boosting 和 bagging 都不仅局限于对决策树这种基模型适应
  5. 如果不是同一种 base model,也可以做集成算法

5、随机森林

5.1、随机森林介绍

Bagging 思想 + 决策树就诞生了随机森林。

随机森林,都有哪些随机?

  • bagging生成一颗决策树时,随机抽样
  • 抽样后,分裂时,每一个结点都随机选择特征,从部分特征中筛选最优分裂条件

image.png

5.2、随机森林实战

1、导包加载数据

import numpy as np
from sklearn import tree
from sklearn import datasets
from sklearn.model_selection import train_test_split
import graphviz
# ensemble 集成
# 随机森林
from sklearn.ensemble import RandomForestClassifier
# 作为对照
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
# 加载数据
X,y = datasets.load_iris(return_X_y=True)
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 112)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

2、普通决策树

score = 0
for i in range(100):
    X_train,X_test,y_train,y_test = train_test_split(X,y)
    model = DecisionTreeClassifier()
    model.fit(X_train,y_train)
    score += model.score(X_test,y_test)/100
print('随机森林平均准确率是:',score)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3、随机森林(运行时间稍长,10s)

score = 0
for i in range(100):
    X_train,X_test,y_train,y_test = train_test_split(X,y)
    model = RandomForestClassifier()
    model.fit(X_train,y_train)
    score += model.score(X_test,y_test)/100
print('随机森林平均准确率是:',score)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结论:

  • 和决策树对比发现,随机森林分数稍高,结果稳定
  • 即降低了结果方差,减少错误率

4、逻辑斯蒂回归

import warnings
warnings.filterwarnings('ignore')
score = 0
for i in range(100):
    X_train,X_test,y_train,y_test = train_test_split(X,y)
    lr = LogisticRegression()
    lr.fit(X_train,y_train)
    score += lr.score(X_test,y_test)/100
print('逻辑斯蒂回归平均准确率是:',score)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

结论:

  • 逻辑斯蒂回归这个算法更加适合鸢尾花这个数据的分类
  • 随机森林也非常优秀

5.3、随机森林可视化

1、创建随机森林进行预测

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 9)
forest = RandomForestClassifier(n_estimators=100,criterion='gini')
forest.fit(X_train,y_train)
score1 = round(forest.score(X_test,y_test),4)
print('随机森林准确率:',score1)
print(forest.predict_proba(X_test))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、对比决策树

X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 112)
model = DecisionTreeClassifier()
model.fit(X_train,y_train)
print('决策树准确率:',model.score(X_test,y_test))
proba_ = model.predict_proba(X_test)
print(proba_)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

总结:

  • 一般情况下,随机森林比决策树更加优秀
  • 随机森林,是多棵树投票的概率,所以predict_proba()概率值,出现0.97
  • 单一决策树,不是,通过投票,而是通过决策树叶节点分类,所以概率要么是0,要么是1

3、绘制决策树

# 第一颗树类别
dot_data = tree.export_graphviz(forest[0],filled=True)
graph = graphviz.Source(dot_data)
graph
  • 1
  • 2
  • 3
  • 4

image.png

# 第五十颗树类别
dot_data = tree.export_graphviz(forest[49],filled=True)
graph = graphviz.Source(dot_data)
graph
  • 1
  • 2
  • 3
  • 4

image.png

# 第100颗树类别
dot_data = tree.export_graphviz(forest[-1],filled=True)
graph = graphviz.Source(dot_data)
graph
  • 1
  • 2
  • 3
  • 4

image.png

5.4、随机森林总结

随机森林主要步骤:

  • 随机选择样本(放回抽样);
  • 随机选择特征;
  • 构建决策树;
  • 随机森林投票(平均)

优点:

  • 表现良好
  • 可以处理高维度数据(维度随机选择)
  • 辅助进行特征选择
  • 得益于 Bagging 可以进行并行训练

缺点:

  • 对于噪声过大的数据容易过拟合

6、极限森林

6.1、极限森林介绍

极限森林,都有哪些随机?

  • 极限森林中每一个决策树都采用原始训练集
  • 抽样后,分裂时,每一个结点分裂时,都进行特征随机抽样(一部分特征作为分裂属性)
  • 从分裂随机中筛选最优分裂条件

image.png

6.2、极限森林实战

1、加载数据

import warnings
warnings.filterwarnings('ignore')
import numpy as np
from sklearn.ensemble import RandomForestClassifier,ExtraTreesClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn import datasets
from sklearn.model_selection import train_test_split
import graphviz
from sklearn import tree

# 加载数据
X,y = datasets.load_wine(True)
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 119)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2、单棵决策树

clf = DecisionTreeClassifier()
clf.fit(X_train,y_train)
print('单棵决策树得分:',clf.score(X_test,y_test))
print('数据特征:',clf.n_features_)
print('节点分裂选择最大特征数量:',clf.max_features_)
  • 1
  • 2
  • 3
  • 4
  • 5

3、随机森林

clf2 = RandomForestClassifier()
clf2.fit(X_train,y_train)
print('随机森林得分:',clf2.score(X_test,y_test))
print('数据特征:',clf2.n_features_)
for t in clf2:
    print('节点分裂选择最大特征数量:',t.max_features_)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4、极限森林

clf3 = ExtraTreesClassifier(max_depth = 3)
clf3.fit(X_train,y_train)
print('极限森林得分:',clf3.score(X_test,y_test))
print('数据特征:',clf3.n_features_)
for t in clf3:
    print('节点分裂选择最大特征数量:',t.max_features_)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

5、可视化

dot_data = tree.export_graphviz(clf3[0],filled=True)
graph = graphviz.Source(dot_data)
graph
  • 1
  • 2
  • 3

image.png

dot_data = tree.export_graphviz(clf3[49],filled=True)
graph = graphviz.Source(dot_data)
graph
  • 1
  • 2
  • 3

image.png

6、分裂标准代码演练

6.1、计算未分裂gini系数

count = []
for i in range(3):
    count.append((y_train == i).sum())
count = np.array(count)
p = count / count.sum()
gini = (p * (1 - p)).sum()
print('未分裂,gini系数是:',round(gini,3))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6.2、根据属性寻找最佳分裂条件

f = np.sort(X_train[:,11])
gini_lower = 1
best_split = {}
for i in range(len(f) - 1):
    split = round(f[i:i + 2].mean(),3)
    cond = X_train[:,11] <= split
    part1 = y_train[cond]
    part2 = y_train[~cond]
    # 计算每一部分的gini系数
    count1 = []
    count2 = []
    for j in range(3):
        count1.append((part1 == j).sum())
        count2.append((part2 == j).sum())
    count1,count2 = np.array(count1),np.array(count2)
    p1 = count1 / count1.sum()
    p2 = count2 / count2.sum()
    gini1 = round((p1 * (1 - p1)).sum(),3)
    gini2 = round((p2 * (1 - p2)).sum(),3)
    # 计算整体的gini系数
    gini = round(gini1 * count1.sum()/(y_train.size) + gini2 * count2.sum()/(y_train.size),3)
    if gini < gini_lower:
        gini_lower = gini
        best_split.clear()
        best_split[j] = split
    print(split,gini1,gini2,gini,count1,count2)
print(best_split,gini_lower)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

结论:

  • 通过打印输出可知,极限森林分裂条件,并不是最优的
  • 并没有使用gini系数最小的分裂点
  • 分裂值,具有随机性,这正是极限森林的随机所在!
注:本文转载自blog.csdn.net的道友老李的文章"https://blog.csdn.net/u014608435/article/details/144554407"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top