【人工智能-18】机器学习:决策树、随机森林
上一期【人工智能-17】机器学习:KNN算法、模型选择和调优、朴素贝叶斯分类
文章目录
- 一、决策树
- 1.使用理由
- 2.技术
- 二、随机森林
- 1.使用理由
- 2.原理核心:Bagging + 随机特征子集
- 3.优点和缺点
一、决策树
决策树是一种监督学习算法,主要用于分类(预测离散标签,如“是/否”、“猫/狗/鸟”)和回归(预测连续值,如房价、温度)任务。
它的模型结构像一棵倒置的树:
-
根节点 (Root Node): 包含整个数据集,代表最开始要判断的特征。
-
内部节点 (Internal Node / Decision Node): 代表一个特征或属性上的测试。基于测试结果,数据被分割到不同的子节点。
-
分支 (Branches): 代表一个特征测试的可能结果(例如,特征“年龄”的分支可能是“年龄<30”和“年龄>=30”)。
-
叶节点 (Leaf Node / Terminal Node): 代表最终的决策结果(分类标签或回归值)。数据到达叶节点后不再分割。
构建决策树的过程就是通过一系列“如果…那么…”的规则,将复杂的数据集逐步分割成更小、更“纯净”的子集,直到达到停止条件(如子集足够纯净、达到最大深度、包含样本数太少等)。
1.使用理由
高度可解释性: 这是决策树最核心的优势!生成的树结构可以被直观地可视化和理解,决策规则清晰透明(白盒模型),容易向非技术人员解释预测背后的逻辑。这在需要理解模型决策过程的应用中(如金融风控、医疗诊断辅助)至关重要。
对数据预处理要求相对较低:
-
能直接处理分类特征和数值特征(数值特征需要选择分割点)。
-
对特征的尺度(量纲)不敏感(因为决策是基于值比较,而不是距离计算)。
-
对缺失值有一定容忍度(可以通过特定策略处理,如分配到出现频率最高的分支,或单独创建分支)。
能够捕捉特征之间的非线性关系: 通过树的分支结构,可以自然地建模特征之间复杂的相互作用和非线性模式。
计算效率较高(训练和预测): 训练算法(如ID3, C4.5, CART)相对高效,预测新样本的速度非常快,只需要沿着树从根节点走到一个叶节点即可。
2.技术
决策树构建的核心在于如何选择“最佳”特征和分割点来分裂节点,目标是让分裂后的子节点尽可能“纯净”。衡量“纯净度”的标准主要有两种:
- 基于信息增益 (Information Gain )
- 信息熵 (Entropy): 衡量数据集
D
的不确定性(混乱度)。熵越高,表示数据类别越混杂;熵为0,表示所有样本都属于同一类。公式核心思想:对每个类别k
,计算其占比p_k
,然后求和-p_k * log2(p_k)
。p_k
越平均(接近0.5),熵越大。 - 信息增益 (IG): 衡量使用某个特征
A
对数据集D
进行分割后,不确定性减少的程度。- 计算分裂前数据集
D
的熵H(D)
。 - 根据特征
A
的每个可能取值(或分割点)将D
分成若干子集D_v
。 - 计算分裂后所有子集的熵的加权平均值
H(D|A)
(权重是子集样本数占总样本数的比例)。 - 信息增益
IG(D, A) = H(D) - H(D|A)
。
- 计算分裂前数据集
- 特征选择: 选择能带来最大信息增益的特征进行当前节点的分裂。信息增益越大,意味着使用该特征分裂后,子集变得更“纯净”(不确定性降低得最多)。
- 缺点: 信息增益倾向于选择取值数目多的特征(如“身份证号”),因为分裂后子集纯度容易更高(极端情况每个样本一个子集,熵为0),但这会导致过拟合且没有泛化能力。
- 改进:信息增益率 (Gain Ratio - C4.5算法): 引入一个惩罚项,称为“分裂信息”
SplitInfo(A)
,它衡量按特征A
分裂时产生的分支数量的多少(分支越多,SplitInfo(A)
越大)。信息增益率GR(D, A) = IG(D, A) / SplitInfo(A)
。这抑制了对取值多特征的偏好。
- 信息熵 (Entropy): 衡量数据集
- 基于基尼指数 (Gini Index / Gini Impurity )
- 基尼指数: 衡量从数据集
D
中随机抽取两个样本,它们属于不同类别的概率。概率越大,基尼指数越高,数据越不纯。公式核心思想:对每个类别k
,计算其占比p_k
,然后求和1 - Σ(p_k²)
。p_k
越平均(接近0.5),基尼指数越高(最大0.5);p_k
越偏向0或1(纯),基尼指数越低(最小0)。 - 特征选择:
- 计算分裂前数据集
D
的基尼指数Gini(D)
。 - 根据特征
A
的每个可能取值(或分割点)将D
分成若干子集D_v
。 - 计算分裂后所有子集的基尼指数的加权平均值
Gini(D|A)
。 - 选择能使
Gini(D|A)
最小(即分裂后子集纯度提升最大)的特征进行分裂。等价于选择能使基尼指数减少量(基尼增益)最大的特征。
- 计算分裂前数据集
- 特点: 基尼指数计算比熵稍快(不用算log),实践中效果通常与信息增益/信息增益率相似。CART算法使用基尼指数,并且其构建的树是二叉树(每次分裂只产生两个子节点),对数值特征处理更自然(寻找一个最佳分割点)。
- 基尼指数: 衡量从数据集
# 决策树 对葡萄酒进行分类
# 基于信息增益的决策树
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
# 获取数据
x,y = load_wine(return_X_y=True)# 划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=22)# 模型训练
# 当模型训练时,criterion参数可以指定信息增益的计算方式,默认是gini,也可以指定为entropy
model = DecisionTreeClassifier(criterion='entropy')
model.fit(x_train,y_train)
print('准确率\n',model.score(x_test,y_test))
print('预测结果\n',model.predict(x_test))# 基于基尼指数的决策树
# 当criterion='gini'时,使用基尼指数
gini = DecisionTreeClassifier(criterion='gini')
gini.fit(x_train,y_train)
print('准确率\n',gini.score(x_test,y_test))
print('预测结果\n',gini.predict(x_test))
二、随机森林
- 随机森林是一种基于Bagging(Bootstrap Aggregating)集成学习思想,并引入了随机特征选择的算法。它的核心是构建多棵决策树(称为“森林”),并通过投票(分类)或平均(回归)的方式结合这些树的预测结果,从而获得比单一决策树更优、更稳定的性能。
- 简单来说:随机森林 = Bagging + 随机特征子集 + 决策树(通常是CART树)。
1.使用理由
- 显著提高泛化能力,减少过拟合: 这是使用随机森林最根本的理由。单一决策树容易过拟合。通过集成大量略微不同且不完全过拟合的树,随机森林能够有效地降低模型的方差(Variance),提高在未知数据上的预测精度和鲁棒性。
- 提升预测准确性和稳定性: 通过“众人智慧”(多棵树投票/平均),随机森林通常能获得比单棵决策树以及其他许多单一模型更高的预测准确率。同时,它对训练数据的小扰动不敏感,结果更稳定。
- 处理高维特征: 在每棵树分裂节点时只考虑随机选取的部分特征(而不是全部),这在高维数据中非常有效,能降低计算量并减少不相关特征的干扰。
- 提供特征重要性评估: 随机森林可以方便地计算出每个特征对预测结果的相对重要性,有助于特征选择和理解数据。
- 保留决策树的部分优点: 虽然可解释性不如单棵树,但仍然能处理混合类型特征、对量纲不敏感、能捕捉非线性关系等。
2.原理核心:Bagging + 随机特征子集
随机森林的训练过程如下:
- Bagging (Bootstrap Aggregating):
- 从原始训练集
D
中有放回地随机抽取N
个样本(形成一个Bootstrap
样本集D_i
)。这意味着每个样本集D_i
的大小与D
相同,但包含重复样本,且平均约有 63.2% 的原始样本会被抽中,剩下的约 36.8% 成为该树的袋外样本 (Out-Of-Bag, OOB),可用于评估该树的性能或特征重要性。 - 重复上述过程
T
次,得到T
个不同的 Bootstrap 训练集{D_1, D_2, ..., D_T}
。
- 从原始训练集
- 构建决策树 (使用随机特征子集):
- 对于每个 Bootstrap 训练集
D_i
,独立地训练一棵决策树。 - 关键点:在训练每棵树的每个内部节点进行分裂时,不是从所有
M
个特征中选择最优特征,而是先随机选取m
个特征(m
通常远小于M
,如m = sqrt(M)
或m = log2(M)
+ 1),然后从这m
个特征中选择最优特征进行分裂。 - 让树完全生长或接近完全生长(通常不剪枝或轻微剪枝),以达到低偏差(Bias)。通过集成来降低方差。
- 对于每个 Bootstrap 训练集
- 聚合预测 (Aggregation):
- 分类任务: 对于新样本,让
T
棵树分别进行预测,然后采用多数投票法(Majority Voting)决定最终的类别标签。 - 回归任务: 对于新样本,让
T
棵树分别进行预测,然后取所有预测值的平均值作为最终预测值。
- 分类任务: 对于新样本,让
核心思想:
- Bagging: 通过 Bootstrap 抽样引入样本扰动,构建多样化的树(减少因数据扰动引起的方差)。
- 随机特征子集: 在节点分裂时随机选择特征子集,强制树之间产生差异(降低树与树之间的相关性),进一步增加模型的多样性(减少因特征选择相关性引起的方差)。
- 集成: 结合多个独立、多样化且具有低偏差的弱学习器(树)的预测结果,通过“平均”效应显著降低整体模型的方差,提高泛化能力。
# 随机森林
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split,GridSearchCV# 获取数据
x,y = load_wine(return_X_y=True)# 划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=22)# 模型训练
# n_estimators: 树的数量 默认100 max_depth: 树的最大深度 默认None criterion: 决策树属性划分算法选择 默认gini enteropy是信息增益
Model = RandomForestClassifier(n_estimators=100,max_depth=None,criterion='gini')
param_grid = {'max_depth':[3,5,10,20],'n_estimators':[100,200,300,400,500]}
# 使用超参数网格搜索,寻找最佳参数
enstimators = GridSearchCV(Model,param_grid=param_grid,cv=5)
enstimators.fit(x_train,y_train)# 模型评估
print('准确率:\n',enstimators.score(x_test,y_test))
print('预测结果:\n',enstimators.predict(x_test))# 获取最佳参数
print('最佳参数:\n',enstimators.best_params_)
# 获取最佳模型
print('最佳模型:\n',enstimators.best_estimator_)
3.优点和缺点
- 优点:
- 高精度: 通常在分类和回归任务中表现出色,预测准确性高。
- 鲁棒性强: 对噪声数据和异常值不太敏感。
- 不易过拟合: 得益于Bagging和特征随机性,即使树很深,整体模型也较难过拟合(相比单棵树)。
- 处理高维特征: 能有效处理特征数量很多的数据集。
- 提供特征重要性: 可以评估特征对预测的贡献度。
- 并行化训练: 每棵树的训练是完全独立的,可以轻松并行化,加速训练过程。
- 内置验证: 袋外样本 (OOB) 可以用于无偏估计模型的泛化误差,无需额外验证集。
- 保留决策树部分优点: 处理混合特征、非线性关系等。
- 缺点:
- 模型可解释性降低: 虽然比“黑箱”模型(如神经网络)稍好,但由成百上千棵树组成的森林难以直观解释单个预测(牺牲了单棵树的最大优势)。
- 训练时间和内存消耗较大: 需要训练多棵树,尤其是在树很深或树的数量
T
很大时。预测速度虽然单次很快,但需要遍历所有树,比单棵树慢T
倍(但仍通常很快)。 - 可能产生偏差较大的模型: 如果数据噪声很大或特征与目标关系很弱,随机森林可能会学到有偏差的模型(虽然方差低)。
- 对某些类型的数据关系(如线性关系)可能不如专门模型高效: 虽然能处理,但可能不如线性模型简单直接。
- 超参数需要调整: 树的数量
T
、每次分裂考虑的特征数m
、树的最大深度等超参数需要调整以获得最佳性能(尽管通常比SVM等调参简单,且T
越大一般越好,但有计算成本)。