本文从理论基础、代码实践、内容总结三个方面来展示预测的三大基础模型与手动调参自动调参内容细节。
一、理论基础
ridgeRegression
Ridge Regression(岭回归)是一种用于线性回归分析的正则化方法,旨在解决多重共线性问题并降低模型的方差。其原理在于通过在损失函数中加入一个正则化项来约束模型参数的大小,从而避免过拟合。岭回归的损失函数是普通最小二乘损失与参数的L2范数(即参数平方和)的加权和,公式可以表示为:
ridgeRegression自动调参方法
自动调参是寻找模型最佳超参数的过程,对于岭回归而言,最重要的超参数就是正则化强度αα。常见的自动调参方法有:
网格搜索(Grid Search):预先设定一系列候选的α值,然后在这些值组成的网格上遍历,对每个值训练模型并评估性能,选择性能最优的α值。
随机搜索(Randomized Search):与网格搜索相比,随机搜索不是遍历所有预设值,而是从参数的定义域中随机抽取一组值进行评估,这种方法在参数空间较大时更为高效。
交叉验证(Cross-Validation):通常与上述搜索方法结合使用,用来评估模型在不同划分的数据集上的性能,以减少因数据划分造成的偶然性,常用的有k折交叉验证。
在实践中,选择哪种自动调参方法取决于问题的复杂性、计算资源的可用性以及对调参效率和精度的要求。许多机器学习库,如Python的Scikit-learn,提供了实现这些自动调参方法的工具和接口,方便用户进行模型优化。
如果数据的特征比样本点还多应该怎么办?是否还可以使用线性回归和之前的方法来做预测?答案是否定的,即不能再使用前面介绍的方法。这是因为输入数据的矩阵X不是满秩矩阵。非满秩矩阵在求逆时会出现问题。为了解决这个问题,统计学家引入了岭回归(ridge regression)的概念。
缩减 : 岭回归最先用来处理特征数多于样本数的情况,现在也用于在估计中加入偏差,从而得到更好的估计,这里通过引入数学公式: $ \lambda $ 来限制了所有w之和,通过引入该惩罚项,能减少不重要的参数,这个技术在统计学中也叫缩减。
作用:1.岭回归可以解决特征数量比样本量多的问题
2.岭回归作为一种缩减算法可以判断哪些特征重要或者不重要,有点类似于降维的效果
3.缩减算法可以看作是对一个模型增加偏差的同时减少方差
适用范围:1.数据点少于变量个数
2.变量间存在共线性(最小二乘回归得到的系数不稳定,方差很大
偏差(Bias):预测值和真实值之间的误差
方差(Variance):预测值之间的离散程度,也就是离其期望值的距离。方差越大,数据的分布越分散。
lightgbm
决策树与CART
1976年-1986年,J.R.Quinlan给出ID3算法原型并进行了总结,确定了决策树学习的理论。这可以看做是决策树算法的起点。1993,Quinlan将ID3算法改进成C4.5算法,称为机器学习的十大算法之一。ID3算法的另一个分支是CART(Classification adn Regression Tree, 分类回归决策树),用于预测。这样,决策树理论完全覆盖了机器学习中的分类和回归两个领域。
决策树(decision tree)一般都是自上而下的来生成的。每个决策或事件(即自然状态)都可能引出两个或多个事件,导致不同的结果,把这种决策分支画成图形很像一棵树的枝干,故称决策树。
决策树利用树结构进行决策,每一个非叶子节点是一个判断条件,每一个叶子节点是结论。从跟节点开始,经过多次判断得出结论。
决策树的构建是数据逐步分裂的过程,构建的步骤如下:
步骤1:将所有的数据看成是一个节点,进入步骤2;
步骤2:从所有的数据特征中挑选一个数据特征对节点进行分割,进入步骤3;
步骤3:生成若干孩子节点,对每一个孩子节点进行判断,如果满足停止分裂的条件,进入步骤4;否则,进入步骤2;
步骤4:设置该节点是子节点,其输出的结果为该节点数量占比最大的类别。
从上述步骤可以看出,决策生成过程中有三个重要的问题:
(1)数据如何分割
(2)如何选择分裂的属性
(3)什么时候停止分裂
决策树(decision tree)算法基于特征属性进行分类,其主要的优点:模型具有可读性,计算量小,分类速度快。
集成学习
集成学习就是将多个弱的学习器结合起来组成一个强的学习器。
这就涉及到,先产生一组'个体学习器',再用一个策略将它们结合起来。
个体学习器可以选择:决策树,神经网络。
集成时可以所有个体学习器属于同一类算法:全是决策树,或全是神经网络;也可以来自不同的算法。
结合策略:例如分类问题,可以用投票法,少数服从多数。
之所以用这种集成的思想,是因为单独用一个算法时,效果往往不容易达到很好,但如果多个个体算法结合在一起,取长补短,整体效果就会比单独一个要强。
当然集成并不是不管怎么选择学习器,怎么组合都一定会获得更好的效果,最好的情况是,每个学习器都不是特别差,并且要具有一定的多样性,否则可能集成后的会没有效果,或者起负作用。
这就是集成学习的一个核心问题:如何生成准确性又不是很差,并且还能保证多样性的个体学习器呢
目前主要有两种生成方式:
Boosting:个体学习器间存在强依赖关系,必须串行生成。
Bagging,随机森林:个体之间不存在强依赖关系,可并行生成。
Boosting
Boosting 的思想,三个臭皮匠顶一个诸葛亮:
给定初始训练数据,由此训练出第一个基学习器;
根据基学习器的表现对样本进行调整,在之前学习器做错的样本上投入更多关注;
用调整后的样本,训练下一个基学习器;
重复上述过程 T 次,将 T 个学习器加权结合。
简单讲,就是每次训练单个弱学习器时,都将上一次分错的数据权重提高一点再进行当前单个弱学习器的学习。这样越往后执行,训练出的单个弱学习器就会越在意那些容易分错(权重高)的点。当执行 M 次后,通过加权求和的方式组合成一个最终的学习器。
Boosting模型可以抽象为一个前向加法模型(additive model):
根据 Boosting 的定义,它有三个基本要素:
基学习器
组合方式
目标函数
AdaBoost
Boosting 的代表是 Adaboost。
• 第 1 行,初始化样本权重分布,此时每个数据的权重是一样的,所以是 1/m;
以分类问题为例,最初令每个样本的权重都相等,对于第 t 次迭代操作,我们就根据这些权重来选取样本点,进而训练分类器 C_t。
• 第 2 行,进入 for 循环 T 次,即基学习器的个数为 T 个;
• 第 3 行,根据具有当前权重分布 D_t 的数据集,学习出 h_t;
前一个分类器分错的样本会被用来训练下一个分类器。
h_t 是分量分类器 C_t 给出的对任一样本点 xi 的标记(+1或-1),h_t(xi) = yi 时,样本被正确分类。
• 第 4 行,计算当前学习器的误差;
• 第 5 行,如果误差大于 0.5,就停止;
AdaBoost 方法中使用的分类器可能很弱(比如出现很大错误率),但只要它的分类效果比随机好一点(比如两类问题分类错误率略小于0.5),就能够改善最终得到的模型。
• 第 6 行,计算当前学习器的权重 α_t;
权值是关于误差的表达式,当下一次分类器再次错分这些点之后,会提高整体的错误率,这样就导致分类器权值变小,进而导致这个分类器在最终的混合分类器中的权值变小,也就是说,Adaboost算法让正确率高的分类器占整体的权值更高,让正确率低的分类器权值更低,从而提高最终分类器的正确率。
• 第 7 行,得到下一时刻的权重分布 D_t+1.
如果某个样本点已经被准确地分类,那么在构造下一个训练集中,它被选中的概率就被降低;相反,如果某个样本点没有被准确地分类,那么它的权重就得到提高。通过这样的方式,AdaBoost 方法能"聚焦于"那些较难分(更富信息)的样本上。
机器学习神经网络------Adaboost分离器算法
Gradient Boosting
AdaBoost每一轮基学习器训练过后都会更新样本权重,再训练下一个学习器,最后将所有的基学习器加权组合。AdaBoost使用的是指数损失,这个损失函数的缺点是对于异常点非常敏感,因而通常在噪音比较多的数据集上表现不佳。Gradient Boosting在这方面进行了改进,使得可以使用任何损失函数 (只要损失函数是连续可导的),这样一些比较robust的损失函数就能得以应用,使模型抗噪音能力更强。
和Adaboost不同,Gradient Boosting 在迭代的时候选择梯度下降的方向来保证最后的结果最好。
算法将负梯度作为残差值来学习基本模型h(x).
GBDT(Gradient Boosting Decision Tree) 梯度提升决策树
DT-Decision Tree决策树,GB是Gradient Boosting,是一种学习策略,GBDT的含义就是用Gradient Boosting的策略训练出来的DT模型。在前几年深度学习还没有大行其道之前,GBDT在各种竞赛是大放异彩。一是效果确实挺不错。二是即可以用于分类也可以用于回归。三是可以筛选特征。
LightGBM = XGBoost + Histogram + GOSS + EFB。
XGBoost,全称eXtreme Gradient Boosting ,简称XGB,是GBDT算法的一种变种,是一种监督算法;它是boost算法的一种,也属于集成算法,是一种伸缩性强、便捷的可并行构建模型的Gradient Boosting算法。其高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广泛应用在Kaggle竞赛及其他许多机器学习竞赛中。并取得了不错的成绩。它可用于分类,回归,排序问题。
XGBoost与GBDT比较大的不同就是目标函数的定义,基本思想是一致的,同样是利用加法模型与前向分步算法实现学习的优化过程。预测过程如下:
其中,f_k表示回归X树,K为回归树的数量。
XGBoost是由GBDT发展而来,同样是利用加法模型与前向分步算法实现学习的优化过程,但与GBDT是有区别的。主要区别包括以下几点:
1、传统的GBDT以CART树作为基学习器,XGBoost还支持线性分类器(线性回归、逻辑回归),这个时候XGBoost相当于L1和L2正则化的逻辑斯蒂回归(分类)或者线性回归(回归);
2、传统的GBDT在优化的时候只用到一阶导数信息,XGBoost则对代价函数进行了二阶泰勒展开,得到一阶和二阶导数==;
3、XGBoost在代价函数中加入了正则项,用于控制模型的复杂度。从权衡方差偏差来看,它降低了模型的方差,使学习出来的模型更加简单,防止过拟合,这也是XGBoost优于传统GBDT的一个特性;
4、shrinkage(缩减或者学习速率),相当于学习速率(XGBoost中的eta)。XGBoost在进行完一次迭代时,会将叶子节点的权值乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间。(GBDT也有学习速率);
5、列抽样。XGBoost借鉴了随机森林的做法,支持列抽样,不仅防止过拟合,还能减少计算;对缺失值的处理。对于特征的值有缺失的样本,XGBoost还可以自动学习出它的分裂方向;
6、XGBoost工具支持并行。Boosting不是一种串行的结构吗?怎么并行的?注意XGBoost的并行不是tree粒度的并行,XGBoost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含了前面t-1次迭代的预测值)。XGBoost的并行是在特征粒度上的。我们知道,决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),XGBoost在训练之前,预先对数据进行了排序,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。
性质 有监督,分类,回归,排序
与GBDT区别
目标函数:XGBoost的损失函数添加了正则化项,使用正则用以控制模型的复杂度,正则项里包含了树的叶子节点个数、每个叶子节点权重(叶结点的socre值)的平方和。
优化方法:GBDT在优化时只使用了一阶导数信息,XGBoost在优化时使用了一、二阶导数信息。
缺失值处理:XBGoost对缺失值进行了处理,通过学习模型自动选择最优的缺失值默认切分方向,分别对左右侧计算损失值,那个小就划分到那一侧,并记录下来额,预测试也按这个标准来,否则默认左侧。
防止过拟合: XGBoost除了增加了正则项来防止过拟合,还支持行列采样的方式来防止过拟合。
结果:它可以在最短时间内用更少的计算资源得到更好的结果。
回归
分类
LightGBM在XGBoost上主要有3方面的优化。
1,Histogram算法:直方图算法。
2,GOSS算法:基于梯度的单边采样算法。
3,EFB算法:互斥特征捆绑算法。
XGBoost生成一片叶子的复杂度可以粗略估计为 = 特征数量候选分裂点数量 样本的数量。
Histogram算法的主要作用是减少候选分裂点数量,
GOSS算法的作用是减少样本的数量,
EFB算法的作用是减少特征的数量。
通过这3个算法的引入,LightGBM生成一片叶子需要的复杂度大大降低了,从而极大节约了计算时间。 同时Histogram算法还将特征由浮点数转换成0~255位的整数进行存储,从而极大节约了内存存储。
Histogram直方图算法
直方图算法是替代XGBoost的预排序(pre-sorted)算法的。预排序算法首先将样本按照特征取值排序,然后从全部特征取值中找到最优的分裂点位,该算法的候选分裂点数量与样本数量成正比。而直方图算法通过将连续特征值离散化到固定数量(如255个)的bins上,使得候选分为点位为常数个(num_bins -1)。
此外,直方图算法还能够作直方图差加速。当节点分裂成两个时,右边叶子节点的直方图等于其父节点的直方图减去左边叶子节点的直方图。从而大大减少构建直方图的计算量。
利用直方图对于每个特征的所有候选分割点按照其范围分成N个箱子,累加箱子内的梯度提升值,对于箱子里的每个候选分割点都计算 带来的梯度增益,对于每个箱子分别保存其累计梯度、箱子内的样本数量。之后再分裂节点时直接对直方图遍历进行分割点的候选即可,通过直方图的方式,虽然分割的精度变差了,但是对最后的结果影响不大,一方面能够提升计算效率,另一方面这种较粗的分割点可以起到一种正则化的效果。之后进行结点分裂时候,只需要根据梯度之和计算loss即可。对Gain增益的计算在梯度计算中。
GOSS基于梯度的单边采样算法
GOSS算法全称为Gradient-based One-Side Sampling,即基于梯度的单边采样算法。 样本的梯度越小,则样本的训练误差越小,表示样本已经训练的很好了。最直接的做法就是丢掉这部分样本,然而直接扔掉会影响数据的分布,因此lightGBM采用了one-side 采样
EFB互斥特征捆绑算法
EFB算法全称是Exclusive Feature Bundling,即互斥特征绑定算法。(将多个特征捆绑到一起)
EFB是通过特征捆绑的方式减少特征维度(其实是降维技术)的方式,来提升计算效率。通常被捆绑的特征都是互斥的(一个特征值为零,一个特征值不为零),这样两个特征捆绑起来才不会丢失信息。如果两个特征并不是完全互斥(部分情况下两个特征都是非零值),可以用一个指标对特征不互斥程度进行衡量,称之为冲突比率,当这个值较小时,我们可以选择把不完全互斥的两个特征捆绑,而不影响最后的精度。
EFB的算法步骤如下:
将特征按照非零值的个数进行排序
计算不同特征之间的冲突比率
遍历每个特征并尝试合并特征,使冲突比率最小化
LightGBM是一种基于梯度提升决策树(Gradient Boosting Decision Tree, GBDT)的机器学习算法,由Microsoft开发,因其高效的训练速度和优秀的预测性能而受到广泛关注。它的核心改进在于以下几个方面:
- 基于 Leaf-Wise 生长策略的树结构:与传统的 Level-Wise 策略(如XGBoost中使用的)不同,LightGBM采用按叶子节点分裂的策略,每次从当前所有叶子节点中找到增益最大的一个进行分裂,这样可以更快地减小损失函数,但也可能带来过拟合的风险,因此需要合适的正则化控制。
- 直方图算法:LightGBM在训练过程中使用了直方图近似方法来加速特征分桶和计算信息增益,减少了计算特征值和分割点之间增益所需的计算量,显著提升了训练效率。
- 单边梯度算法(GOSS, Gradient-based One-Side Sampling)和独家特征捆绑(EFB, Exclusive Feature Bundling):这两种算法进一步提高了训练速度和模型的内存效率,GOSS通过只使用一部分数据来估计梯度,而EFB则通过捆绑互斥特征减少特征的数量。
对于LightGBM的自动调参,常用的有以下几种方法: - Hyperopt:这是一个Python库,能够进行分布式异步超参数优化。通过定义搜索空间、目标函数(通常是交叉验证得分)和优化算法(如TPE),Hyperopt可以自动探索参数空间,找到最优配置。
- Optuna:另一个流行的超参数优化库,提供了简洁的API来定义和执行超参数搜索。Optuna支持多种采样策略,并能自动适应地优化参数。
- Grid Search:尽管效率较低,但在参数空间较小或预先有较好参数范围的情况下,网格搜索仍然是一种可行的选择,它会遍历所有预设的参数组合。
- Random Search:随机选择参数组合进行尝试,比网格搜索更高效,尤其在参数空间较大时,通常能得到较好的结果。
LightGBM有许多参数,以下是一些关键参数及其作用:
num_leaves:控制树的最大叶子节点数,直接影响模型的复杂度和过拟合风险。
learning_rate:学习率,每次迭代更新权重的步长,较小的学习率需要更多的迭代次数,但通常能有更好的泛化能力。
max_depth:在Leaf-Wise策略中,这个参数的意义不如num_leaves明显,但在某些情况下仍可作为限制树深度的手段。
min_child_samples(min_data_in_leaf):叶子节点上所需的最小样本数,用于防止过拟合。
colsample_bytree(feature_fraction):每棵树随机选取特征的比例,用于特征的随机子抽样。
subsample(bagging_fraction):训练数据的子采样比例,用于行的随机子抽样,减少过拟合风险。
lambda_l1和lambda_l2:L1和L2正则化项的权重,用于防止模型过拟合。
objective:目标函数,根据任务类型(如二分类、多分类、回归)选择。
metric:评价模型性能的指标,应与目标函数相匹配。
合理选择和调优这些参数对于达到模型的最佳性能至关重要。实践中,通常结合交叉验证和上述自动调参方法来确定最优参数配置。
catboost
catboost=Gradient Boosting(梯度提升) + Categorical Features(类别型特征)
CatBoost 与 XGBoost 、LightGBM是主流的三大Boosting框架,都是高效的GBDT算法工程化实现框架。CatBoost 则因长于处理类别特征而取名为CatBoost(Categorical + Boosting)。算法的理论特色,包括用于处理类别变量的目标变量统计和排序提升算法。
CatBoost是一种基于对称决策树(oblivious trees)为基学习器实现的参数较少、支持类别型变量和高准确性的GBDT框架,主要解决的痛点是高效合理地处理类别型特征,这一点从它的名字中可以看出来,CatBoost是由Categorical和Boosting组成。此外,CatBoost还解决了梯度偏差(Gradient Bias)以及预测偏移(Prediction shift)的问题,从而减少过拟合的发生,进而提高算法的准确性和泛化能力。
与XGBoost、LightGBM相比,CatBoost的创新点有:
嵌入了自动将类别型特征处理为数值型特征的创新算法。首先对categorical features做一些统计,计算某个类别特征(category)出现的频率,之后加上超参数,生成新的数值型特征(numerical features)。
Catboost还使用了组合类别特征,可以利用到特征之间的联系,这极大的丰富了特征维度。
采用排序提升的方法对抗训练集中的噪声点,从而避免梯度估计的偏差,进而解决预测偏移的问题。
采用了完全对称树作为基模型。
XGBoost被广泛的应用于工业界,LightGBM有效的提升了GBDT的计算效率,而Yandex的CatBoost号称是比XGBoost和LightGBM在算法准确率等方面表现更为优秀的算法。
CatBoost是一种基于对称决策树(oblivious trees)为基学习器实现的参数较少、支持类别型变量和高准确性的GBDT框架,主要解决的痛点是高效合理地处理类别型特征,CatBoost是由Categorical和Boosting组成。此外,CatBoost还解决了梯度偏差(Gradient Bias)及预测偏移(Prediction shift)的问题,从而减少过拟合的发生,进而提高算法的准确性和泛化能力
它自动采用特殊的方式处理类别型特征(categorical features)。首先对categorical features做一些统计,计算某个类别特征(category)出现的频率,之后加上超参数,生成新的数值型特征(numerical features)。这也是我在这里介绍这个算法最大的motivtion,有了catboost,再也不用手动处理类别型特征了。
catboost还使用了组合类别特征,可以利用到特征之间的联系,这极大的丰富了特征维度。
采用ordered boost的方法避免梯度估计的偏差,进而解决预测偏移的问题。
catboost的基模型采用的是对称树,同时计算leaf-value方式和传统的boosting算法也不一样,传统的boosting算法计算的是平均数,而catboost在这方面做了优化采用了其他的算法,这些改进都能防止模型过拟合。
Categorical features
所谓类别型特征,即这类特征不是数值型特征,而是离散的集合,比如省份名(山东、山西、河北等),城市名(北京、上海、深圳等),学历(本科、硕士、博士等)。在梯度提升算法中,最常用的是将这些类别型特征转为数值型来处理,一般类别型特征会转化为一个或多个数值型特征。
如果某个类别型特征基数比较低(low-cardinality features),即该特征的所有值去重后构成的集合元素个数比较少,一般利用One-hot编码方法将特征转为数值型。One-hot编码可以在数据预处理时完成,也可以在模型训练的时候完成,从训练时间的角度,后一种方法的实现更为高效,CatBoost对于基数较低的类别型特征也是采用后一种实现。
在高基数类别型特征(high cardinality features) 当中,比如 user ID,这种编码方式会产生大量新的特征,造成维度灾难。一种折中的办法是可以将类别分组成有限个的群体再进行 One-hot encoding。一种常被使用的方法是根据目标变量统计(Target Statistics,以下简称TS)进行分组,目标变量统计用于估算每个类别的目标变量期望值。甚至有人直接用TS作为一个新的数值型变量来代替原来的类别型变量。重要的是,可以通过对TS数值型特征的阈值设置,基于对数损失、基尼系数或者均方差,得到一个对于训练集而言将类别一分为二的所有可能划分当中最优的那个。在LightGBM当中,类别型特征用每一步梯度提升时的梯度统计(Gradient Statistics,以下简称GS)来表示。虽然为建树提供了重要的信息,但是这种方法有以下两个缺点:
增加计算时间,因为需要对每一个类别型特征,在迭代的每一步,都需要对GS进行计算;
增加存储需求,对于一个类别型变量,需要存储每一次分离每个节点的类别。
为了克服这些缺点,LightGBM以损失部分信息为代价将所有的长尾类别归位一类,作者声称这样处理高势特征时比起 One-hot encoding还是好不少。不过如果采用TS特征,那么对于每个类别只需要计算和存储一个数字。如此看到,采用TS作为一个新的数值型特征是最有效、信息损失最小的处理类别型特征的方法。TS也被广泛采用,在点击预测任务当中,这个场景当中的类别特征有用户、地区、广告、广告发布者等。接下来我们着重讨论TS,暂时将One-hot encoding和GS放一边。
Target Statistics
CatBoost算法的设计初衷是为了更好的处理GBDT特征中的categorical features。在处理 GBDT特征中的categorical features的时候,最简单的方法是用 categorical feature 对应的标签的平均值来替换。在决策树中,标签平均值将作为节点分裂的标准。这种方法被称为 Greedy Target-based Statistics , 简称 Greedy TS,用公式来表达就是:
这种方法有一个显而易见的缺陷,就是通常特征比标签包含更多的信息,如果强行用标签的平均值来表示特征的话,当训练数据集和测试数据集数据结构和分布不一样的时候会出条件偏移问题。一个标准的改进 Greedy TS的方式是添加先验分布项,这样可以减少噪声和低频率类别型数据对于数据分布的影响
其中p是添加的先验项,a通常是大于0的权重系数。添加先验项是一个普遍做法,针对类别数较少的特征,它可以减少噪声数据。。对于回归问题,一般情况下,先验项可取数据集label的均值。对于二分类,先验项是正例的先验概率。
当然,在论文《CatBoost: unbiased boosting with categorical features》中,还提到了其它几种改进Greedy TS的方法,分别有:Holdout TS、Leave-one-out TS、Ordered TS。
Ordered TS
它是catboost的主要思想,依赖于排序,受online learning algorithms的启发得到,对于某一个样本,TS的值依赖于观测历史,为了在离线的数据上应用该思想,我们将数据随机排序,对于每一个样本,利用该样本之前数据计算该样本类别值的TS值。如果仅仅使用一个随机序列,那么计算得到值会有较大的方差,因此我们使用不同的随机序列来计算。
特征组合
CatBoost的另外一项重要实现是将不同类别型特征的组合作为新的特征,以获得高阶依赖(high-order dependencies),比如在广告点击预测当中用户ID与广告话题之间的联合信息,又或者在音乐推荐引用当中,用户ID和音乐流派,如果有些用户更喜欢摇滚乐,那么将用户ID和音乐流派分别转换为数字特征时,这种用户内在的喜好信息就会丢失。然而,组合的数量会随着数据集中类别型特征的数量成指数增长,因此在算法中考虑所有组合是不现实的。为当前树构造新的分割点时,CatBoost会采用贪婪的策略考虑组合。对于树的第一次分割,不考虑任何组合。对于下一个分割,CatBoost将当前树的所有组合、类别型特征与数据集中的所有类别型特征相结合,并将新的组合类别型特征动态地转换为数值型特征。CatBoost还通过以下方式生成数值型特征和类别型特征的组合:树中选定的所有分割点都被视为具有两个值的类别型特征,并像类别型特征一样地被进行组合考虑。
CatBoost处理Categorical features总结
首先会计算一些数据的statistics。计算某个category出现的频率,加上超参数,生成新的numerical features。这一策略要求同一标签数据不能排列在一起(即先全是之后全是这种方式),训练之前需要打乱数据集。
第二,使用数据的不同排列。在每一轮建立树之前,先扔一轮骰子,决定使用哪个排列来生成树。
第三,考虑使用categorical features的不同组合。例如颜色和种类组合起来,可以构成类似于blue dog这样的特征。当需要组合的categorical features变多时,CatBoost只考虑一部分combinations。在选择第一个节点时,只考虑选择一个特征,例如A。在生成第二个节点时,考虑A和任意一个categorical feature的组合,选择其中最好的。就这样使用贪心算法生成combinations。
第四,除非向gender这种维数很小的情况,不建议自己生成One-hot编码向量,最好交给算法来处理。
梯度偏差/预测偏移
为什么会有梯度偏差?
梯度偏差造成了什么问题?
如何解决梯度偏差?
为什么会有梯度偏差?
CatBoost和所有标准梯度提升算法一样,都是通过构建新树来拟合当前模型的梯度。然而,所有经典的提升算法都存在由有偏的点态梯度估计引起的过拟合问题。在每个步骤中使用的梯度都使用当前模型中的相同的数据点来估计,这导致估计梯度在特征空间的任何域中的分布与该域中梯度的真实分布相比发生了偏移。
梯度偏差造成了什么问题?
模型过拟合,预测发生偏移。另外预测偏移还有当我们利用TS来处理类别特征时,引起的target leak的问题。
如何解决梯度偏差/预测偏移?
为了解决这个问题,CatBoost对经典的梯度提升算法进行了一些改进,简要介绍如下:
许多利用GBDT技术的算法(例如,XGBoost、LightGBM),构建下一棵树分为两个阶段:选择树结构和在树结构固定后计算叶子节点的值。为了选择最佳的树结构,算法通过枚举不同的分割,用这些分割构建树,对得到的叶子节点计算值,然后对得到的树计算评分,最后选择最佳的分割。两个阶段叶子节点的值都是被当做梯度或牛顿步长的近似值来计算。
在CatBoost中,第一阶段采用梯度步长的无偏估计,第二阶段使用传统的GBDT方案执行。既然原来的梯度估计是有偏的,那么怎么能改成无偏估计呢。
快速评分
CatBoost使用对称树(oblivious trees)作为基预测器。在这类树中,相同的分割准则在树的整个一层上使用。这种树是平衡的,不太容易过拟合。梯度提升对称树被成功地用于各种学习任务中。在对称树中,每个叶子节点的索引可以被编码为长度等于树深度的二进制向量。这在CatBoost模型评估器中得到了广泛的应用:我们首先将所有浮点特征、统计信息和独热编码特征进行二值化,然后使用二进制特征来计算模型预测值。
算法流程
优点
性能卓越: 在性能方面可以匹敌任何先进的机器学习算法;
鲁棒性/强健性: 无需调参即可获得较高的模型质量,采用默认参数就可以获得非常好的结果,减少在调参上面花的时间,减少了对很多超参数调优的需求
易于使用: 提供与scikit集成的Python接口,以及R和命令行界面;
实用: 可以处理类别型、数值型特征,支持类别型变量,无需对非数值型特征进行预处理
可扩展: 支持自定义损失函数;
快速、可扩展的GPU版本,可以用基于GPU的梯度提升算法实现来训练你的模型,支持多卡并行提高准确性,
快速预测:即便应对延时非常苛刻的任务也能够快速高效部署模型
缺点
对于类别型特征的处理需要大量的内存和时间;
不同随机数的设定对于模型预测结果有一定的影响;
CatBoost是俄罗斯Yandex公司开发的一种梯度提升决策树算法,它在GBDT的基础上进行了多项改进,尤其擅长处理类别特征和防止过拟合。其核心原理和特性包括:
- 自动处理类别特征:CatBoost无需手动编码类别特征,自动对类别特征进行独热编码前的统计处理,计算类别频率并结合超参数生成数值特征,大大简化了特征工程。
- 对称决策树(Oblivious Trees):CatBoost使用了对称决策树,即树的所有内部节点都分裂到相同的深度,这减少了模型的复杂度,加快了训练速度,并有助于防止过拟合。
- 防止梯度偏差和预测偏移:通过对目标变量分布进行修正,CatBoost在每一轮迭代中补偿训练数据和预测数据之间的差异,减少预测偏移。
- 提前计算分割:在训练开始时,CatBoost预先计算了每个特征的最优分割点,减少了训练过程中的计算量。
- 模型融合:CatBoost支持训练多个模型并进行模型融合,以提高预测性能。
CatBoost提供了内置的自动调参功能,同时也可以结合第三方库进行调参。常用的自动调参方法包括: - 内置Grid Search:CatBoost本身提供了基于网格搜索的超参数优化方法,用户可以指定一系列候选值,让算法在这些值中寻找最优组合。
- Optuna与Hyperopt:这两个第三方库通过贝叶斯优化等策略进行超参数调优,能够在较大的参数空间中高效探索,找到较优参数配置。Optuna和Hyperopt均支持动态调整搜索策略,根据前期的评估结果智能地选择后续待测试的参数组合。
- Custom Scripting:开发者可以编写自定义脚本来实现更复杂的调参逻辑,结合交叉验证等策略,手动或半自动地遍历参数空间。
CatBoost的参数众多,以下是一些重要的参数及其含义:
learning_rate:学习率,控制每一步梯度下降的幅度。
depth:决策树的最大深度。
l2_leaf_reg:L2正则化项的权重,用于防止过拟合。
iterations:迭代次数,即构建的树的数量。
loss_function:损失函数,根据任务类型选择,如分类任务中的Logloss、多分类的MultiClass等。
eval_metric:评估模型性能的指标。
random_seed:随机种子,用于确保实验的可复现性。
cat_features:指定数据集中类别特征的列索引列表。
bootstrap_type:是否进行行采样,以及采样的类型,如'Bernoulli'或'MVS'。
实际操作中,结合交叉验证和上述自动调参方法,可以有效地寻找模型的最佳超参数配置,提升预测性能。
交叉验证
图片: https://uploader.shimo.im/f/kYDL0jjlMMti8ani.png!thumbnail?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MTY0NzcwNzMsImZpbGVHVUlEIjoiWnprTE1ybTJyQlQwR3BBUSIsImlhdCI6MTcxNjQ3Njc3MywiaXNzIjoidXBsb2FkZXJfYWNjZXNzX3Jlc291cmNlIiwidXNlcklkIjo3MzYwMzI4MH0.TMcJ3EETKk3DuZFGzcUMyRthfkf3GUVPSd6CKslcFBU
回到交叉验证,根据切分的方法不同,交叉验证分为下面三种:
第一种是简单交叉验证,所谓的简单,是和其他交叉验证方法相对而言的。首先,我们随机的将样本数据分为两部分(比如: 70%的训练集,30%的测试集),然后用训练集来训练模型,在测试集上验证模型及参数。接着,我们再把样本打乱,重新选择训练集和测试集,继续训练数据和检验模型。最后我们选择损失函数评估最优的模型和参数。
第二种是 S折交叉验证( S-Folder Cross Validation),也是经常会用到的。和第一种方法不同, S折交叉验证先将数据集 D随机划分为 S个大小相同的互斥子集,即 ,每次随机的选择 S-1份作为训练集,剩下的1份做测试集。当这一轮完成后,重新随机选择 S份来训练数据。若干轮(小于 S )之后,选择损失函数评估最优的模型和参数。注意,交叉验证法评估结果的稳定性和保真性在很大程度上取决于 S取值。
第三种是留一交叉验证(Leave-one-out Cross Validation),它是第二种情况的特例,此时 S等于样本数 N,这样对于 N个样本,每次选择 N-1个样本来训练数据,留一个样本来验证模型预测的好坏。此方法主要用于样本量非常少的情况,比如对于普通适中问题, N小于50时,我一般采用留一交叉验证。
通过反复的交叉验证,用损失函数来度量得到的模型的好坏,最终我们可以得到一个较好的模型。那这三种情况,到底我们应该选择哪一种方法呢?一句话总结,如果我们只是对数据做一个初步的模型建立,不是要做深入分析的话,简单交叉验证就可以了。否则就用S折交叉验证。在样本量少的时候,使用S折交叉验证的特例留一交叉验证。
此外还有一种比较特殊的交叉验证方式,也是用于样本量少的时候。叫做自助法(bootstrapping)。比如我们有m个样本(m较小),每次在这m个样本中随机采集一个样本,放入训练集,采样完后把样本放回。这样重复采集m次,我们得到m个样本组成的训练集。当然,这m个样本中很有可能有重复的样本数据。同时,用原始的m个样本做测试集。这样接着进行交叉验证。由于我们的训练集有重复数据,这会改变数据的分布,因而训练结果会有估计偏差,因此,此种方法不是很常用,除非数据量真的很少,比如小于20个。
保留交叉验证 hand-out cross validation
首先随机地将已给数据分为两部分:训练集和测试集 (例如,70% 训练集,30% 测试集);
然后用训练集在各种条件下 (比如,不同的参数个数) 训练模型,从而得到不同的模型;
在测试集上评价各个模型的测试误差,选出测试误差最小的模型。
这种方式其实严格意义上并不能算是交叉验证,因为训练集的样本数始终是那么多,模型并没有看到更多的样本,没有体现交叉的思想。
由于是随机的将原始数据分组,所以最后测试集上准确率的高低与原始数据的分组有很大的关系,所以这种方法得到的结果其实并不具有说服性。
k折交叉验证 k-fold cross validation
首先随机地将数据集切分为 k 个互不相交的大小相同的子集;
然后将 k-1 个子集当成训练集训练模型,剩下的 (held out) 一个子集当测试集测试模型;
将上一步对可能的 k 种选择重复进行 (每次挑一个不同的子集做测试集);
这样就训练了 k 个模型,每个模型都在相应的测试集上计算测试误差,得到了 k 个测试误差,对这 k 次的测试误差取平均便得到一个交叉验证误差。这便是交叉验证的过程。
计算平均测试误差 (交叉验证误差) 来评估当前参数下的模型性能。
在模型选择时,假设模型有许多 tuning parameter 可供调参,一组 tuning parameter 便确定一个模型,计算其交叉验证误差,最后选择使得交叉验证误差最小的那一组 tuning parameter。这便是模型选择过程。
k 一般大于等于2,实际操作时一般从3开始取,只有在原始数据集样本数量小的时候才会尝试取2。
k折交叉验证可以有效的避免过拟合以及欠拟合状态的发生,最后得到的结果也比较具有说服性。
k折交叉验证最大的优点:
• 所有数据都会参与到训练和预测中,有效避免过拟合,充分体现了交叉的思想
交叉验证可能存在 bias 或者 variance。如果我们提高切分的数量 k,variance 会上升但 bias 可能会下降。相反得,如果降低 k,bias 可能会上升但 variance 会下降。bias-variance tradeoff 是一个有趣的问题,我们希望模型的 bias 和 variance 都很低,但有时候做不到,只好权衡利弊,选取他们二者的平衡点。
通常使用10折交叉验证,当然这也取决于训练数据的样本数量。
留一交叉验证 leave-one-out cross validation
k折交叉验证的特殊情况,k=N,N 是数据集的样本数量,往往在数据缺乏的情况下使用。
留一交叉验证的优点是:
• 每一回合中几乎所有的样本皆用于训练模型,因此最接近原始样本的分布,这样评估所得的结果比较可靠。
• 实验过程中没有随机因素会影响实验数据,确保实验过程是可以被复制的。
缺点是:
• 计算成本高,因为需要建立的模型数量和原始数据集样本数量一致,尤其当样本数量很大的时候。可以考虑并行化训练模型减少训练时间。
总之,交叉验证对于我们选择模型以及模型的参数都是很有帮助的。
但以上交叉验证的方法都有一个问题,就是在数据分组的时候缺乏随机性,以 k折交叉验证 为例,每个数据样本只能固定属于 k 个子集中的一个,可能会造成对于最终结果的影响。于是有人提出了 bootstrapping。
Bootstrapping
cv 和 bootstrapping 都是重采样 (resampling) 的方法。机器学习中常用的 bagging 和 boosting 都是 bootstrapping 思想的应用。
bootstrapping 的思想是依靠自己的资源,称为自助法,它是一种有放回的抽样方法。
bootstrapping 的过程如下:
数据假设要分成10组,则先设置一个采样比例,比如采样比例70%。则10组数据是每次从原始数据集中随机采样总数70%的数据构成训练集1,没有选中的样本作为测试集1;然后把数据放回,再随机采样总数70%的数据构成训练集2,没选中的作为测试集2......以此类推,放回式采样10组。
训练生成10个模型
计算平均测试误差来评估当前参数下的模型性能
除此之外,bootstrapping 在集成学习方法中也很有用。比如我们可以用经过bootstrapping 的多组数据集构建模型 (比如决策树),然后将这些模型打包 (bag,就像随机森林),最后使用这些模型的最大投票结果作为我们最终的输出。
交叉验证(Cross-validation)是一种统计学方法,广泛应用于机器学习和统计建模中,旨在评估模型的泛化能力,即模型在未见过的数据上的表现。其核心思想是将数据集分成训练集和测试集,通过多次迭代,轮流使用不同的数据子集进行训练和测试,以此来估计模型在未知数据上的性能。
基本原理步骤如下: - 数据分割:首先,将数据集随机分成k个大小相似的子集(或"折"),其中k-1个子集用于模型训练,剩下的1个子集用于模型验证或测试。这个过程重复k次,每次轮流选择不同的子集作为验证集,其余作为训练集。
- 模型训练与验证:在每一次迭代中,使用选定的k-1个子集训练模型,然后在保留的子集上评估模型性能。评估标准通常包括准确率、精确度、召回率、F1分数或AUC-ROC曲线等,具体取决于任务类型。
- 性能评估:所有k次迭代后,计算每个验证集上的性能指标,并取这些指标的平均值作为模型整体性能的估计。这样的平均值相比单一划分的训练/测试更能代表模型在新数据上的预期表现,因为它考虑到了模型在不同子集上的稳定性和一般性。
常见的交叉验证类型包括:
简单交叉验证(Holdout method):最基础的形式,数据被分为训练集(如70%)和测试集(如30%)。
k折交叉验证(k-fold Cross-validation):如上所述,是最常用的交叉验证方法,k通常取5或10。
留一法交叉验证(Leave-One-Out Cross-validation, LOOCV):极端情况下的k折交叉验证,k等于数据集的样本数,每个样本单独作为验证集。
分层k折交叉验证(Stratified k-fold Cross-validation):适用于分类问题,确保每个折叠中的类比例与原数据集相同。
时间序列交叉验证(Time-Series Cross-validation):适用于时间序列数据,保持时间顺序,确保训练集在时间上早于测试集。
通过交叉验证,不仅可以评估模型的性能,还可以用于模型选择,即在多个模型或同一模型的不同超参数设置间比较,选择最优模型。这种方法有助于减少过拟合的风险,提高模型的泛化能力。
hyperopt自动调参
图片: https://uploader.shimo.im/f/91Fatq8IO1HYM0p9.png!thumbnail?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MTY0NzcwNzMsImZpbGVHVUlEIjoiWnprTE1ybTJyQlQwR3BBUSIsImlhdCI6MTcxNjQ3Njc3MywiaXNzIjoidXBsb2FkZXJfYWNjZXNzX3Jlc291cmNlIiwidXNlcklkIjo3MzYwMzI4MH0.TMcJ3EETKk3DuZFGzcUMyRthfkf3GUVPSd6CKslcFBU
贝叶斯优化是一种基于模型的用于寻找函数最小值的方法。近段时间以来,贝叶斯优化开始被用于机器学习超参数调优,结果表明,该方法在测试集上的表现更加优异,并且需要的迭代次数小于随机搜索。
Python 环境下有一些贝叶斯优化程序库,它们目标函数的代理算法有所区别。本部分主要介绍「Hyperopt」库,它使用树形 Parzen 评估器(TPE,https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf)作为搜索算法,其他的 Python 库还包含「Spearmint」(高斯过程代理)和「SMAC」(随即森林回归)。
贝叶斯优化问题有四个组成部分:
1)目标函数:我们想要最小化的对象,这里指带超参数的机器学习模型的验证误差
2)域空间:待搜索的超参数值
3)优化算法:构造代理模型和选择接下来要评估的超参数值的方法
4)结果的历史数据:存储下来的目标函数评估结果,包含超参数和验证损失
通过以上四个步骤,我们可以对任意实值函数进行优化(找到最小值)。
详解:
1)目标函数
模型训练目的是最小化目标函数,所以输出为需要最小化的实值------交叉验证损失。Hyperopt 将目标函数作为黑盒处理,因为这个库只关心输入和输出是什么。为了找到使损失最小的输入值。
cross_val_score
对衡量的estimator,它默认返回的是一个array,包含K folder情况下的各次的评分,一般采用mean()。 需要确定这个estimator默认的 scoring 是什么,它的值是越大越匹配还是越小越匹配。如果自己指定了scoring,一定要确定这个scoring值的意义,切记切记! 而如果用户不指定,一般对于Classification类的estimator,使用accuracy,它是越大越好,那么,hyperopt里面的loss的值就应该是对这个值取负数,因为hyperopt通过loss最小取找最佳匹配。 可以把feature的normalize或者scale作为一个choice,然后看看是否更合适。如果更合适,best里面就会显示 normalize 为1。
贝叶斯优化的一个实现,一个名为hyperopt的 Python 模块。
使用贝叶斯优化进行调参可以让我们获得给定模型的最佳参数,例如逻辑回归模型。这也使我们能够执行最佳的模型选择。通常机器学习工程师或数据科学家将为少数模型(如决策树,支持向量机和 K 近邻)执行某种形式(网格搜索或随机搜索)的手动调参,然后比较准确率并选择最佳的一个来使用。该方法可能比较的是次优模型。也许数据科学家找到了决策树的最优参数,但却错过了 SVM 的最优参数。
这意味着他们的模型比较是有缺陷的。如果 SVM 参数调整得很差,K 近邻可能每次都会击败 SVM。贝叶斯优化允许数据科学家找到所有模型的最佳参数,并因此比较最佳模型。这会得到更好的模型选择,因为你比较的是最佳的 k 近邻和最佳的决策树。只有这样你才能非常自信地进行模型选择,确保选择并使用的是实际最佳的模型。
什么是Hyperopt
Hyperopt是一个强大的python库,用于超参数优化,由jamesbergstra开发。Hyperopt使用贝叶斯优化的形式进行参数调整,允许你为给定模型获得最佳参数。它可以在大范围内优化具有数百个参数的模型。
Hyperopt的特性
Hyperopt包含4个重要的特性,你需要知道,以便运行你的第一个优化。
搜索空间
hyperopt有不同的函数来指定输入参数的范围,这些是随机搜索空间。选择最常用的搜索选项:
hp.choice(label, options)-这可用于分类参数,它返回其中一个选项,它应该是一个列表或元组。示例:hp.choice("criterion", ["gini","entropy",])
hp.randint(label, upper)-可用于整数参数,它返回范围(0,upper)内的随机整数。示例:hp.randint("max_features",50)
hp.uniform(label, low, high)-它返回一个介于low和high之间的值。示例:hp.uniform("max_leaf_nodes",1,10)
你可以使用的其他选项包括:
hp.normal(label, mu, sigma)-这将返回一个实际值,该值服从均值为mu和标准差为sigma的正态分布
hp.qnormal(label, mu, sigma, q)-返回一个类似round(normal(mu, sigma) / q) * q的值
hp.lognormal(label, mu, sigma)-返回exp(normal(mu, sigma))
hp.qlognormal(label, mu, sigma, q) -返回一个类似round(exp(normal(mu, sigma)) / q) * q的值
注:每个可优化的随机表达式都有一个标签(例如n_estimators)作为第一个参数。这些标签用于在优化过程中将参数选择返回给调用者。
目标函数
这是一个最小化函数,它从搜索空间接收超参数值作为输入并返回损失。这意味着在优化过程中,我们使用选定的超参数值训练模型并预测目标特征,然后评估预测误差并将其返回给优化器。优化器将决定要检查哪些值并再次迭代。你将在一个实际例子中学习如何创建一个目标函数。
Hyperopt是一个开源的Python库,专门用于自动化地优化机器学习模型的超参数。它通过执行一个高效的搜索过程来寻找最佳的超参数组合,这一过程通常被称为超参数优化或模型调优。Hyperopt的原理主要包括以下几个关键方面: - 超参数空间定义
首先,用户需要定义超参数的取值空间,这包括了超参数的类型(如连续、离散、分类等)及其可能的取值范围。Hyperopt使用一个名为hp.choice、hp.uniform、hp.quniform、hp.loguniform、hp.qloguniform等的函数来定义这些空间。例如,你可以定义学习率在一定区间内的连续取值,或者从几个特定的激活函数中选择。 - 目标函数定义
接下来,需要定义一个目标函数,它衡量模型在给定超参数配置下的性能。这个函数通常会涉及训练模型、在验证集上评估,并返回一个度量值(如交叉验证得分、损失函数值等),该值反映了模型在这个超参数配置下的表现。Hyperopt的目标是寻找使该目标函数值最优的超参数组合。 - 优化算法
Hyperopt的核心是其优化算法,最著名的是其采用的Tree-structured Parzen Estimator (TPE)算法。TPE是一种基于贝叶斯优化的方法,它通过构建两个概率模型(一个用于好的配置,一个用于坏的配置)来指导超参数的搜索。TPE算法在每一步都会根据已有的评估结果来调整搜索方向,优先探索那些看起来更有可能导致高性能配置的区域。这使得搜索更加高效,尤其是在高维参数空间中。 - 分布式和异步特性
Hyperopt支持分布式和异步的超参数优化,这意味着它可以并行运行多个试验(trials),每个试验对应一种超参数配置。这在计算资源充足时能显著加快调参过程。它可以通过队列或更复杂的分布式计算框架来实现这一点。 - 早停机制
为了提高效率,Hyperopt支持自动在训练的早期终止无望的试验(trials),即当模型在初步评估中表现不佳时,系统会自动停止这个试验,转而尝试其他更有可能成功的配置。这一机制称为自动化的early-stopping,有助于节省计算资源。
综上,Hyperopt通过灵活的超参数空间定义、高效的TPE优化算法、分布式异步执行能力以及早停机制,提供了一套强大的超参数优化解决方案,适用于多种机器学习模型和任务,帮助研究者和工程师自动发现最优模型配置。
optuna自动调参
Optuna是一款灵活、高效的超参数优化框架,特别设计用于机器学习模型的调参过程。它通过自动化地探索超参数空间,帮助用户找到模型表现最优的参数组合。下面是Optuna自动调参的基本原理和流程: - 定义目标函数(Objective Function):
这是Optuna调参的核心,你需要定义一个函数,它接收超参数作为输入,然后返回一个评估指标(如交叉验证得分、损失函数值等),该指标反映了模型性能。目标是最大化或最小化这个指标。 - 配置超参数空间:
通过Optuna的建议函数(suggestion functions),如suggest_float, suggest_int, suggest_categorical等,定义超参数的取值范围和类型(连续、整数、分类等)。 - 创建研究(Study):
创建一个Study对象来管理超参数优化的整个过程。在此过程中,你可以指定优化目标是最大化还是最小化目标函数。 - 定义优化方向:
设置优化目标的方向,即确定是寻找最大化还是最小化目标函数值的超参数组合。Optuna通过direction=minimize或direction=maximize来指定。 - 执行优化过程:
使用study.optimize()方法运行优化过程。Optuna会根据你定义的超参数空间和目标函数,自动尝试不同的超参数组合。 - 采样算法:
Optuna采用了多种采样算法,如TPE(Tree-structured Parzen Estimator)、随机搜索、网格搜索等,来智能地探索超参数空间。TPE是Optuna默认且最为推荐的算法,它通过贝叶斯优化原理,根据历史试验结果动态调整搜索策略,以高效找到最优解。 - 剪枝(Pruning):
Optuna支持早停机制,可以在训练过程中根据一定的规则(如基于性能的阈值)提前终止表现不佳的试验,以节省计算资源。 - 结果分析:
完成优化后,可以使用study.best_params获取最佳超参数组合,study.best_value获取最佳目标函数值,还可以进一步分析所有试验的结果,了解超参数之间的关系和探索过程。
Optuna的优势在于其简洁的API设计、内置的并行化支持、以及对多种机器学习库(如TensorFlow、PyTorch、LightGBM、XGBoost等)的兼容性,使得它成为机器学习项目中自动调参的有力工具。
Bayesian Optimization
贝叶斯优化其实就是基于模型的超参数优化,根据已有的采样点预估函数,不断迭代获得最大值的一个算法
图片: https://uploader.shimo.im/f/KTmrntEblVtFlk7I.png!thumbnail?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MTY0NzcwNzMsImZpbGVHVUlEIjoiWnprTE1ybTJyQlQwR3BBUSIsImlhdCI6MTcxNjQ3Njc3MywiaXNzIjoidXBsb2FkZXJfYWNjZXNzX3Jlc291cmNlIiwidXNlcklkIjo3MzYwMzI4MH0.TMcJ3EETKk3DuZFGzcUMyRthfkf3GUVPSd6CKslcFBU
图片: https://uploader.shimo.im/f/spjjrKXZ0urascia.png!thumbnail?accessToken=eyJhbGciOiJIUzI1NiIsImtpZCI6ImRlZmF1bHQiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjE3MTY0NzcwNzMsImZpbGVHVUlEIjoiWnprTE1ybTJyQlQwR3BBUSIsImlhdCI6MTcxNjQ3Njc3MywiaXNzIjoidXBsb2FkZXJfYWNjZXNzX3Jlc291cmNlIiwidXNlcklkIjo3MzYwMzI4MH0.TMcJ3EETKk3DuZFGzcUMyRthfkf3GUVPSd6CKslcFBU
优点
贝叶树优化和网格搜索相比,迭代次数少(节省时间),粒度可以到很小。
搜索方式自动化,不需要太多人工参与。
调参过程可以控制。
缺点
不容易找到全局最优解。
过程比较复杂。
randomsearch自动调参
超参数优化也就是常说的调参,python-sklearn里常用的有GridSearchCV和RandomizedSearchCV可以用。其中GridSearchCV的原理很简明,就是程序去挨个尝试每一组超参数,然后选取最好的那一组。可以想象,这个是比较费时间的,面临着维度灾难。因此James Bergstra和Yoshua Bengio在2012年提出了超参数优化的RandomSearch方法。
RandomizedSearchCV是在论文的基础上加入了cross-validation
RandomSearchCV是如何"随机搜索"的:
考察其源代码,其搜索策略如下:
(a)对于搜索范围是distribution的超参数,根据给定的distribution随机采样;
(b)对于搜索范围是lit的超参数,在给定的list中等概率采样;
(c)对a、b两步中得到的n_iter组采样结果,进行遍历。
(补充)如果给定的搜索范围均为list,则不放回抽样n_iter次。
随机搜索(Random Search)是一种简单的超参数优化方法,它在超参数的定义范围内随机抽取值来进行模型的训练和评估,以期找到性能较好的超参数组合。与网格搜索(Grid Search)相比,随机搜索虽然放弃了对所有可能组合的穷举,但能在更广泛的参数空间里探索,尤其适用于参数空间较大时,能更高效地找到较好的参数配置。以下是随机搜索自动调参的基本原理和步骤: - 定义超参数空间:首先明确各个超参数的取值范围,例如学习率可以在[0.001, 0.1]之间,树的深度可以是[3, 10]之间的整数等。
- 随机抽样:根据超参数空间的定义,随机抽取超参数值的组合。每次抽取都是独立的,且遵循各参数的分布规则(连续参数通常均匀或高斯分布抽取,离散参数则是从定义的集合中随机选取)。
- 模型训练与评估:使用抽取的超参数组合训练模型,并在验证集上评估模型性能。常用的评估指标包括准确率、AUC-ROC、LogLoss等,具体取决于任务类型。
- 重复过程:重复上述抽样、训练和评估步骤多次,以收集多组超参数性能数据。
- 选择最优参数:所有尝试结束后,选择使得模型性能最佳的超参数组合作为最终的超参数设置。
优点:
效率高:特别是当超参数空间很大时,相比网格搜索,随机搜索可以更高效地探索参数空间,因为不需要遍历所有可能的组合。
简单易实现:随机搜索的实现相对简单,不需要复杂的优化算法,容易集成到现有的机器学习管道中。
避免局部最优:由于搜索过程的随机性,有助于跳出局部最优,发现全局或更优的超参数配置。
缺点:
可能错过最优解:由于是随机抽样,即使最优解存在于定义的参数空间内,也可能因为抽样次数有限而未能发现。
缺乏指导性:相比于贝叶斯优化等方法,随机搜索没有利用历史试验的信息来指导后续的搜索,可能不够高效。
随机搜索通常配合交叉验证一起使用,以更稳健地评估模型性能,减少因数据划分的随机性导致的性能评估波动。此外,随机搜索可以在并行计算环境中高效运行,进一步缩短总的调参时间。
gridsearch自动调参
GridSearchCV 是一个在 scikit-learn 库中用于执行网格搜索(grid search)参数调优的方法。网格搜索是一种通过遍历预定义的参数网格来确定机器学习模型最佳超参数组合的技术。
自动调参,适合小数据集。相当于写一堆循环,自己设定参数列表,一个一个试,找到最合适的参数。数据量大可以使用快速调优的方法-----坐标下降【贪心,拿当前对模型影响最大的参数调优,直到最优,但可能获得的是全局最优】。
GridSearchCV.fit(X, y[, groups]) 方法是 sklearn.model_selection.GridSearchCV 类的一个重要方法,用于执行网格搜索过程,即遍历给定的参数网格,并针对每个参数组合利用交叉验证策略训练和评估模型。
调用 GridSearchCV.fit(X, y) 后,实例将保存以下属性,供后续分析和使用:
best_params_: 最佳参数组合,即在交叉验证过程中表现最好的参数设置。
best_estimator_: 使用最佳参数重新拟合得到的模型实例。
best_score_: 在交叉验证过程中,最佳参数组合对应的平均得分(基于指定的 scoring 函数)。
cv_results_: 字典形式的详细结果,包含了所有参数组合、得分、训练时间等信息。
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score='raise', return_train_score='warn')
estimator:所使用的分类器,比如:estimator=RandomForestClassifier(min_samples_split=100, min_samples_leaf=20, max_depth=8, max_features='sqrt', random_state=10),并且传入除需要确定最佳的参数之外的其他参数。每个分类器都需要一个scoring参数或者score方法。
param_grid:值为字典或列表,即需要最优化的参数的取值,param_grid =param_test1,param_test1 = {'n_estimators':range(10,71,10)}
scoring:准确评价标准,默认为None(使用estimator的误差估计函数),这时需要使用score函数;或者如scoring='roc_auc',根据所选模型不同,评价准则不同。
cv:交叉验证参数,默认为None
refit:默认为True,程序将会以交叉验证训练集得到的最佳参数,重新对所有可用的训练集与测试集进行,作为最终用于性能评估的最佳模型参数。即在搜索参数结束后,用最佳参数结果再次fit一遍全部数据集。
iid:默认True,为True时,默认为各个样本fold概率分布一致,误差估计为所有样本之和,而非各个fold的平均。
verbose:日志冗长度,int:冗长度,0:不输出训练过程,1:偶尔输出,>1:对每个子模型都输出。
n_jobs: 并行数,int:个数,-1:跟CPU核数一致, 1:默认值。
pre_dispatch:指定总共分发的并行任务数。当n_jobs大于1时,数据将在每个运行点进行复制,这可能导致OOM,而设置pre_dispatch参数,则可以预先划分总共的job数量,使数据最多被复制pre_dispatch次,进行预测的常用方法和属性
grid.fit():运行网格搜索
grid_scores_:给出不同参数情况下的评价结果
best_params_:描述了已取得最佳结果的参数的组合
best_score_:成员提供优化过程期间观察到的最好的评分
参考:
https://blog.csdn.net/lccever/article/details/80535058
https://zhuanlan.zhihu.com/p/668817682
https://pip.pypa.io/en/latest/topics/configuration/
https://zhuanlan.zhihu.com/p/342297405
https://blog.csdn.net/weixin_43522665/article/details/132051894
https://www.cnblogs.com/wuzc/p/12798173.html
https://www.cnblogs.com/Lee-yl/p/9190192.html
https://www.zhihu.com/question/485089505
https://zhuanlan.zhihu.com/p/660468945
https://blog.csdn.net/m0_56006701/article/details/130832837
https://zhuanlan.zhihu.com/p/672975755
https://blog.51cto.com/u_16099176/10196681
https://www.jianshu.com/p/ded6abd50e5a
https://blog.csdn.net/weixin_42327752/article/details/121428875
https://blog.csdn.net/reept/article/details/135296762
https://zhuanlan.zhihu.com/p/485403000
https://www.cnblogs.com/cgmcoding/p/14447895.html
https://blog.csdn.net/weixin_42691585/article/details/113971857
https://cloud.tencent.com/developer/article/2009339