Bagging是从训练集中进行子抽样组成每个基模型所需要的子训练集,然后对所有基模型预测的结果进行综合操作产生最终的预测结果。
Boosting中基模型按次序进行训练,而基模型的训练集按照某种策略每次都进行一定的转化,最后以一定的方式将基分类器组合成一个强分类器。
Bagging的训练集是在原始集中有放回的选取,而Boosting每轮的训练集不变,只是训练集中的每个样本在分类器中的权重都会发生变化,此权值会根据上一轮的结果进行调整。
Bagging的各个预测函数可以并行生成,Boosting的各预测函数只能顺序生成。
Bagging中整体模型的期望近似于基模型的期望,所以整体模型的偏差相似于基模型的偏差,因此Bagging中的基模型为强模型(强模型拥有低偏差高方差)。
Boosting中的基模型为弱模型,若不是弱模型会导致整体模型的方差很大。
Bagging和Boosting的区别:
1)样本选择上:Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。
2)样例权重:Bagging:使用均匀取样,每个样例的权重相等。Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大。
3)预测函数:Bagging:所有预测函数的权重相等。Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。
4)并行计算:Bagging:各个预测函数可以并行生成。Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。
GDBT在函数空间中利用梯度下降法进行优化而XGB在函数空间中使用了牛顿法进行优化。即GDBT在优化中使用了一阶导数信息,而XGB对损失函数进行了二阶泰勒展开,用到了一阶和二阶倒数信息。XGB在损失函数中加入了正则项(树叶子节点个数,每个叶子节点上输出score的L2模平方和。对于缺失的样本,XGB可以自动学习出它的分裂方向。GDBT的节点分裂方式使用的是gini系数,XGB通过优化推导出分裂前后的增益来选择分裂节点。XGB在处理每个特征列时可以做到并行。
先用一个初始值去学习一棵树,然后在叶子处得到预测值以及预测后的残差,之后的树则基于之前树的残差不断的拟合得到,从而训练出一系列的树作为模型。
n_estimators基学习器的最大迭代次数,learning_rate学习率,max_lead_nodes最大叶子节点数,max_depth树的最大深度,min_samples_leaf叶子节点上最少样本数。
Stacking和blending的区别在于数据的划分,blending用不相交的数据训练不同的基模型,并将其输出取加权平均。而stacking是将数据集划分为两个不相交的集合,在第一个集合的数据集中训练多个模型,在第二个数据集中测试这些模型,将预测结果作为输入,将正确的标签作为输出,再训练一个高层的模型。
AdaBoost通过调整错分的数据点的权重来改进模型,而GBDT是从负梯度的方向去拟合改进模型。
AdaBoost改变了训练数据的权值,即样本的概率分布,减少上一轮被正确分类的样本权值,提高被错误分类的样本权值,而随机森林在训练每棵树的时候,随机挑选部分训练集进行训练。在对新数据进行预测时,AdaBoost中所有树加权投票进行预测,每棵树的权重和错误率有关,而随机森林对所有树的结果按照少数服从多数的原则进行预测。
GBDT 全称为 Gradient Boosting Decision Tree。顾名思义,它是一种基于决策树(decision tree)实现的分类回归算法。
Gradient Descent: method of steepest descent
梯度下降作为求解确定可微方程的常用方法而被人所熟知。它是一种迭代求解过程,具体就是使解沿着当前解所对应梯度的反方向迭代。这个方向也叫做最速下降方向。具体推导过程如下。假定当前已经迭代到第 k 轮结束,那么第 k+1 轮的结果怎么得到呢?我们对函数 f 做如下一阶泰勒展开:
为了使得第k+1 轮的函数值比第 k 轮的小,即如下不等式成立。
则只需使:
按照这样一直迭代下去,直到 ∇f(xk)=0, xk+1=xk ,函数收敛,迭代停止。由于在做泰勒展开时,要求xk+1−xk 足够小。因此,需要γ比较小才行,一般设置为 0~1 的小数。
顺带提一下,Gradient Descent 是一种一阶优化方法,为什么这么说呢?因为它在迭代过程中不需要二阶及以上的信息。如果我们在泰勒展开时,不是一阶展开,而是二阶展开。那对应的方法就是另一个被大家所熟知的可微方程求解方法:Newton Method,关于牛顿法的详细内容,我们会在后续文章介绍。
Boosting: Gradient Descent in functional space
Boosting一般作为一种模型组合方式存在,这也是它在 GBDT 中的作用。那Boosting 与 gradient descent 有什么关系呢?上一节我们说到 gradient descent 是一种确定可微方程的求解方法。这里的可微有一个要求,就是说上文中的损失函数 f 针对模型 x 直接可微。因此模型x可以根据梯度迭代直接求解。而这种损失函数针对模型直接可微是一个很强的假设,不是所有的模型都满足,比如说决策树模型。现在我们回到第一节,将f(x)写的更具体一点:
f(x)=l(h(x,D),Y)
其中D 为数据特征;Y 为数据 label;h 为模型函数,解决由 D->Y 的映射,x为模型函数参数,即通常我们说的模型;l 为目标函数或损失函数。
以逻辑回归为例, x为权重向量, h模型函数展开为:
目标函数l展开为:
我们发现函数1对h可微,同时h对x可微,因此l对x可微。因此,我们可以通过 gradient descent的方式对x进行直接求解,而不用将h保存下来。然而,如果l对h可微,但h对x不可微呢?我们仍按照第一节的方法先对l进行泰勒展开,只不过不是针对x,而是对 h。为了简单起见,我们省略D,Y。
其中:
按照第一节的逻辑,我们不难得出如下迭代公式:
但别忘了,我们的目的不是求 h,而是 x。由于 h 对 x 不可微,所以 x 必须根据数据重新学习得到。而此时我们重新学习 x 的目标已经不是源目标 Y,而是原损失函数 l 在当前 H 处的梯度,即:
这个重新学习x的过程正是每个base weak learner所做的事情。而这种通过weak learner 拟合每一步迭代后的梯度,进而实现weak learner组合的方式,就是Boosting。又由于我们在求导过程中,损失函数l没法对模型x直接求导,而只能对模型函数h求导。因此 Boosting又有一个别名:“函数空间梯度下降“。
此外,你可能会听过boosting的可加性(additive)。这里顺便提一句,可加性指的是 h 的可加,而不是x的可加。比如x是决策树,那两棵决策树本身怎么加在一起呢?你顶多把他们并排放在一起。可加的只是样本根据决策树模型得到的预测值 h(x,D)罢了。
Decision Tree: the based weak learner
Boosting 的本质就是使用每个weak learner来拟合截止到当前的梯度。则这里的D,还是原来数据中的D,而Y已经不是原来的Y了。而GBDT 中的这个weak learner 就是一棵分类回归树(CART)。因此我们可以使用决策树直接拟合梯度:∇l(H(xt))。此时我们要求的x就变成了这样一棵有k个叶子节点的、使得如下目标函数最小化的决策树:
其中T为目标∇l(H(xt)),W为每个叶子节点的权重,L为叶子节点集合。容易求得每个叶子节点的权重为归属到当前叶子节点的样本均值。即 :
每个样本的预测值即为其所归属的叶子节点的权重,即h(xt+1)
Bagging与Boosting的区别:
1)取样方式(样本权重):Bagging是均匀选取,样本的权重相等,Boosting根据错误率取样,错误率越大则权重越大。2)训练集的选择:Bagging随机选择训练集,训练集之间相互独立,Boosting的各轮训练集的选择与前面各轮的学习结果有关。3)预测函数:Bagging各个预测函数没有权重,可以并行生成,Boosting有权重,顺序生成。4)Bagging是减少variance,Boosting是减少bias。
Bagging 是 Bootstrap Aggregating的简称,意思就是再取样 (Bootstrap) 然后在每个样本上训练出来的模型取平均,所以是降低模型的 variance. Bagging 比如 Random Forest 这种先天并行的算法都有这个效果。
Boosting 则是迭代算法,每一次迭代都根据上一次迭代的预测结果对样本进行加权,所以随着迭代不不断进行行,误差会越来越小,所以模型的 bias 会不不断降低。这种算法无法并行。
1)明确损失函数是误差最小
2)构建第一棵回归树
3)学习多棵回归树
迭代:计算梯度/残差gm(如果是均方误差为损失函数即为残差)
步长/缩放因子p,用 a single Newton-Raphson step 去近似求解下降方向步长,通常的实现中 Step3 被省略,采用 shrinkage 的策略通过参数设置步长,避免过拟合:第m棵树fm=p*gm;模型Fm=Fm-1+p*gm
4)F(x)等于所有树结果累加
适用场景:GBDT几乎可用于所有回归问题(线性/非线性),GBDT的适用面非常广。亦可用于二分类问题(设定阈值,大于阈值为正例,反之为负例)。
GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种用于回归的机器学习算法,该算法由多棵回归决策树组成,所有树的结论累加起来做最终答案。当把目标函数做变换后,该算法亦可用于分类或排序。
1)明确损失函数是误差最小
2)构建第一棵回归树
3)学习多棵回归树
迭代:计算梯度/残差gm(如果是均方误差为损失函数即为残差)
步长/缩放因子p,用 a single Newton-Raphson step 去近似求解下降方向步长,通常的实现中 Step3 被省略,采用 shrinkage 的策略通过参数设置步长,避免过拟合
第m棵树fm=p*gm
模型Fm=Fm-1+p*gm
4)F(x)等于所有树结果累加
GBDT和RF都是集成方法中的经典模型,我们需要弄清楚下面几个问题:1)GBDT是采用boosing方法,RF采用的是baggging方法;2)bias和variance是解释模型泛化性能的,其实还有噪声。
然后,理解GBDT和RF执行原理,其中GBDT中的核心是通过用分类器(如CART、RF)拟合损失函数梯度,而损失函数的定义就决定了在子区域内各个步长,其中就是期望输出与分类器预测输出的查,即bias;而RF的核心就是自采样(样本随机)和属性随机(所有样本中随机选择K个子样本选择最优属性来划分),样本数相同下的不同训练集产生的各个分类器,即数据的扰动导致模型学习性能的变化,即variance。
Gradient boosting Decision Tree(GBDT)
GB算法中最典型的基学习器是决策树,尤其是CART,正如名字的含义,GBDT是GB和DT的结合。要注意的是这里的决策树是回归树,GBDT中的决策树是个弱模型,深度较小一般不会超过5,叶子节点的数量也不会超过10,对于生成的每棵决策树乘上比较小的缩减系数(学习率<0.1),有些GBDT的实现加入了随机抽样(subsample 0.5<=f <=0.8)提高模型的泛化能力。通过交叉验证的方法选择最优的参数。
Random Forest:
bagging (你懂得,原本叫Bootstrap aggregating),bagging 的关键是重复的对经过bootstrapped采样来的观测集子集进行拟合。然后求平均。。。一个bagged tree充分利用近2/3的样本集。。。所以就有了OOB预估(outof bag estimation)
GBDT和随机森林的相同点:
1)都是由多棵树组成;2)最终的结果都是由多棵树一起决定
GBDT和随机森林的不同点:
1)组成随机森林的树可以是分类树,也可以是回归树;而GBDT只由回归树组成;
2)组成随机森林的树可以并行生成;而GBDT只能是串行生成;
3)对于最终的输出结果而言,随机森林采用多数投票等;而GBDT则是将所有结果累加起来,或者加权累加起来;
4)随机森林对异常值不敏感,GBDT对异常值非常敏感;
5)随机森林对训练集一视同仁,GBDT是基于权值的弱分类器的集成;
6)随机森林是通过减少模型方差提高性能,GBDT是通过减少模型偏差提高性能。
RF决策树:
学习随机森林模型前,一定要先了解决策树模型。树越深,模型越复杂。
决策树模型的优点如下。1)容易理解和解释,树可以被可视化。2)不需要太多的数据预处理工作,即不需要进行数据归一化,创造哑变量等操作。3)隐含地创造了多个联合特征,并能够解决非线性问题。
GBDT决策树:
迭代决策树GBDT(Gradient Boosting Decision Tree)也被称为是MART(Multiple Additive Regression Tree))或者是GBRT(Gradient Boosting Regression Tree),也是一种基于集成思想的决策树模型,但是它和Random Forest有着本质上的区别。不得不提的是,GBDT是目前竞赛中最为常用的一种机器学习算法,因为它不仅可以适用于多种场景,更难能可贵的是,GBDT有着出众的准确率。
树的剪枝:
(1)前剪枝( Pre-Pruning)
通过提前停止树的构造来对决策树进行剪枝,一旦停止该节点下树的继续构造,该节点就成了叶节点。一般树的前剪枝原则有:a.节点达到完全纯度;b.树的深度达到用户所要的深度;c.节点中样本个数少于用户指定个数;d.不纯度指标下降的最大幅度小于用户指定的幅度。
(2)后剪枝( Post-Pruning)
首先构造完整的决策树,允许决策树过度拟合训练数据,然后对那些置信度不够的结点的子树用叶结点来替代。CART 采用Cost-Complexity Pruning(代价-复杂度剪枝法),代价(cost) :主要指样本错分率;复杂度(complexity) :主要指树t的叶节点数,(Breiman…)定义树t的代价复杂度(cost-complexity):信息熵H(X),信息增益=H(D)-H(Y|X),信息增益率=gain(x)/H(x),Gini系数=1-sum(pk^2),基尼系数就是熵在x=1的地方一阶泰勒展开得到f(x)=1-x,所以gini=sum[x(1-x)]=1-sum(x^2)。
1)随机森林采用的bagging思想,而GBDT采用的boosting思想。这两种方法都是Bootstrap思想的应用,Bootstrap是一种有放回的抽样方法思想。虽然都是有放回的抽样,但二者的区别在于:Bagging采用有放回的均匀取样,而Boosting根据错误率来取样(Boosting初始化时对每一个训练样例赋相等的权重1/n,然后用该算法对训练集训练t轮,每次训练后,对训练失败的样例赋以较大的权重),因此Boosting的分类精度要优于Bagging。Bagging的训练集的选择是随机的,各训练集之间相互独立,弱分类器可并行,而Boosting的训练集的选择与前一轮的学习结果有关,是串行的。2)组成随机森林的树可以是分类树,也可以是回归树;而GBDT只能由回归树组成。3)组成随机森林的树可以并行生成;而GBDT只能是串行生成。4)对于最终的输出结果而言,随机森林采用多数投票等;而GBDT则是将所有结果累加起来,或者加权累加起来。5)随机森林对异常值不敏感;GBDT对异常值非常敏感。6)随机森林对训练集一视同仁;GBDT是基于权值的弱分类器的集成。7)随机森林是通过减少模型方差提高性能;GBDT是通过减少模型偏差提高性能。
Xgboost根据结构分数的增益情况计算出来选择哪个特征作为分割点,而某个特征的重要性就是它在所有树中出现的次数之和。
XGBoost是一个树集成模型,它使用的是K(树的总数为K)个树的每棵树对样本的预测值的和作为该样本在XGBoost系统中的预测,定义函数如下:
对于所给的数据集有n个样本,m个特征,定义为:
其中Xi表示第i个样本,yi表示第i个样本的类别标签。CART树的空间为F,如下:
其中q表示每棵树的结构映射每个样本到相应的叶节点的分数,即q表示树的模型,输入一个样本,根据模型将样本映射到叶节点输出预测的分数;Wq(x)表示树q的所有叶节点的分数组成集合;T是树q的叶节点数量。
所以,由(1)式可以看出,XGBoost的预测值为每棵树的预测值之和,即每棵树相应的叶节点的得分之和(Wi的和,Wi表示第i个叶节点的得分)。
我们的目标就是学习这样的K个树模型f(x).。为了学习模型f(x),我们定义下面的目标函数:
其中,(2)式右边第一项为损失函数项,即训练误差,是一个可微的凸函数(比如用于回归的均方误差和用于分类的Logistic误差函数等),第二项为正则化项,即每棵树的复杂度之和,目的是控制模型的复杂度,防止过拟合。我们的目标是在L(φ)取得最小化时得出对应的模型f(x)。
由于XGBoost模型中的优化参数是模型f(x),不是一个具体的值,所以不能用传统的优化方法在欧式空间中进行优化,而是采用additive training的方式去学习模型。每一次保留原来的模型不变,加入一个新的函数f到模型中,如下:
预测值在每一次迭代中加入一个新的函数f目的是使目标函数尽量最大地降低。
因为我们的目标是最小化L(φ)时得到模型f(x),但是L(φ)中并没有参数f(x),所以,我们将上图中的最后一式代入L(φ)中可得到如下式子:
对于平方误差(用于回归)来说(3)式转换成如下形式:
对于不是平方误差的情况下,一般会采用泰勒展开式来定义一个近似的目标函数,以方便我们的进一步计算。
根据如下的泰勒展开式,移除高阶无穷小项,得:
(3)式等价于下面的式子:
由于我们的目标是求L(φ)最小化时的模型f(x)(也是变量),当移除常数项时模型的最小值变化,但是取最小值的变量不变(比如:y=x^2+C,无论C去何值,x都在0处取最小值)。所以,为了简化计算,我们移除常数项,得到如下的目标函数:
定义 为叶节点j的实例,重写(4)式,将关于树模型的迭代转换为关于树的叶子节点的迭代,得到如下过程:
此时我们的目标是求每棵树的叶节点j的分数Wj,求出Wj后,将每棵树的Wj相加,即可得到最终的预测的分数。而要想得到最优的Wj的值,即最小化我们的目标函数,所以上式对Wj求偏导,并令偏导数为0,算出此时的W*j为:
将W*j代入原式得:
方程(5)可以用作得分(score)函数来测量树结构q的质量。该得分类似于评估决策树的不纯度得分,除了它是针对更广泛的目标函数得出的。
在xgboost调中,一般有两种方式用于控制过拟合:1)直接控制参数的复杂度:包括max_depth min_child_weight gamma;2)add randomness来使得对训练对噪声鲁棒。包括subsample colsample_bytree,或者也可以减小步长 eta,但是需要增加num_round,来平衡步长因子的减小。
Xgboost:
优缺点:1)在寻找最佳分割点时,考虑传统的枚举每个特征的所有可能分割点的贪心法效率太低,xgboost实现了一种近似的算法。大致的思想是根据百分位法列举几个可能成为分割点的候选者,然后从候选者中根据上面求分割点的公式计算找出最佳的分割点。2)xgboost考虑了训练数据为稀疏值的情况,可以为缺失值或者指定的值指定分支的默认方向,这能大大提升算法的效率,paper提到50倍。3)特征列排序后以块的形式存储在内存中,在迭代中可以重复使用;虽然boosting算法迭代必须串行,但是在处理每个特征列时可以做到并行。4)按照特征列方式存储能优化寻找最佳的分割点,但是当以行计算梯度数据时会导致内存的不连续访问,严重时会导致cache miss,降低算法效率。paper中提到,可先将数据收集到线程内部的buffer,然后再计算,提高算法的效率。5)xgboost 还考虑了当数据量比较大,内存不够时怎么有效的使用磁盘,主要是结合多线程、数据压缩、分片的方法,尽可能的提高算法的效率。
适用场景:分类回归问题都可以。
Rf:
优点:1)表现性能好,与其他算法相比有着很大优势。2)随机森林能处理很高维度的数据(也就是很多特征的数据),并且不用做特征选择。3)在训练完之后,随机森林能给出哪些特征比较重要。4)训练速度快,容易做成并行化方法(训练时,树与树之间是相互独立的)。5)在训练过程中,能够检测到feature之间的影响。6)对于不平衡数据集来说,随机森林可以平衡误差。当存在分类不平衡的情况时,随机森林能提供平衡数据集误差的有效方法。7)如果有很大一部分的特征遗失,用RF算法仍然可以维持准确度。8)随机森林算法有很强的抗干扰能力(具体体现在6,7点)。所以当数据存在大量的数据缺失,用RF也是不错的。9)随机森林抗过拟合能力比较强(虽然理论上说随机森林不会产生过拟合现象,但是在现实中噪声是不能忽略的,增加树虽然能够减小过拟合,但没有办法完全消除过拟合,无论怎么增加树都不行,再说树的数目也不可能无限增加的)。10)随机森林能够解决分类与回归两种类型的问题,并在这两方面都有相当好的估计表现。(虽然RF能做回归问题,但通常都用RF来解决分类问题)。11)在创建随机森林时候,对generlization error(泛化误差)使用的是无偏估计模型,泛化能力强。
缺点:1)随机森林在解决回归问题时,并没有像它在分类中表现的那么好,这是因为它并不能给出一个连续的输出。当进行回归时,随机森林不能够做出超越训练集数据范围的预测,这可能导致在某些特定噪声的数据进行建模时出现过度拟合。(PS:随机森林已经被证明在某些噪音较大的分类或者回归问题上回过拟合)。2)对于许多统计建模者来说,随机森林给人的感觉就像一个黑盒子,你无法控制模型内部的运行。只能在不同的参数和随机种子之间进行尝试。3)可能有很多相似的决策树,掩盖了真实的结果。4)对于小数据或者低维数据(特征较少的数据),可能不能产生很好的分类。(处理高维数据,处理特征遗失数据,处理不平衡数据是随机森林的长处)。5)执行数据虽然比boosting等快(随机森林属于bagging),但比单只决策树慢多了。
适用场景:数据维度相对低(几十维),同时对准确性有较高要求时。因为不需要很多参数调整就可以达到不错的效果,基本上不知道用什么方法的时候都可以先试一下随机森林。
Lr:
优点:实现简单,广泛的应用于工业问题上;分类时计算量非常小,速度很快,存储资源低;便利的观测样本概率分数;对逻辑回归而言,多重共线性并不是问题,它可以结合L2正则化来解决该问题。
缺点:当特征空间很大时,逻辑回归的性能不是很好;容易欠拟合,一般准确度不太高
不能很好地处理大量多类特征或变量;只能处理两分类问题(在此基础上衍生出来的softmax可以用于多分类),且必须线性可分;对于非线性特征,需要进行转换。
适用场景:LR同样是很多分类算法的基础组件,它的好处是输出值自然地落在0到1之间,并且有概率意义。因为它本质上是一个线性的分类器,所以处理不好特征之间相关的情况。虽然效果一般,却胜在模型清晰,背后的概率学经得住推敲。它拟合出来的参数就代表了每一个特征(feature)对结果的影响。也是一个理解数据的好工具。
决策树的学习最耗时的一个步骤就是对特征值进行排序,在进行节点分裂时需要计算每个特征的增益,最终选增益大的特征做分裂,各个特征的增益计算就可开启多线程进行。而且可以采用并行化的近似直方图算法进行节点分裂。
(1)xgboost采用的是level-wise的分裂策略,而lightGBM采用了leaf-wise的策略,区别是xgboost对每一层所有节点做无差别分裂,可能有些节点的增益非常小,对结果影响不大,但是xgboost也进行了分裂,带来了务必要的开销。 leaft-wise的做法是在当前所有叶子节点中选择分裂收益最大的节点进行分裂,如此递归进行,很明显leaf-wise这种做法容易过拟合,因为容易陷入比较高的深度中,因此需要对最大深度做限制,从而避免过拟合。
(2)lightgbm使用了基于histogram的决策树算法,这一点不同与xgboost中的 exact 算法,histogram算法在内存和计算代价上都有不小优势。1)内存上优势:很明显,直方图算法的内存消耗为(#data* #features * 1Bytes)(因为对特征分桶后只需保存特征离散化之后的值),而xgboost的exact算法内存消耗为:(2 * #data * #features* 4Bytes),因为xgboost既要保存原始feature的值,也要保存这个值的顺序索引,这些值需要32位的浮点数来保存。2)计算上的优势,预排序算法在选择好分裂特征计算分裂收益时需要遍历所有样本的特征值,时间为(#data),而直方图算法只需要遍历桶就行了,时间为(#bin)
(3)直方图做差加速,一个子节点的直方图可以通过父节点的直方图减去兄弟节点的直方图得到,从而加速计算。
(4)lightgbm支持直接输入categorical 的feature,在对离散特征分裂时,每个取值都当作一个桶,分裂时的增益算的是”是否属于某个category“的gain。类似于one-hot编码。
(5)xgboost在每一层都动态构建直方图,因为xgboost的直方图算法不是针对某个特定的feature,而是所有feature共享一个直方图(每个样本的权重是二阶导),所以每一层都要重新构建直方图,而lightgbm中对每个特征都有一个直方图,所以构建一次直方图就够了。
其适用场景根据实际项目和两种算法的优点进行选择。