集成思想是机器学习中重要的思想之一,kaggle中常用的的xgboost就是集成的应用。其基本框架是:假如你有一打分类器(我们称之为基分类器),假设这些分类器有不同的属性,将这些基分类器结合起来, 会有意想不到的效果,这篇文章记录的事集成思想的两种重要表现:Bagging与Boosting。本文是李宏毅老师ML Lecture22: Ensemble的笔记,建议大家去观看原视频。

Bagging

假设现在有N笔数据,每次从这N笔数据中sample出N个样本,就是通过这样的方式可以sample出多个database,接下来用一个复杂的模型对每个resample的database做训练,就得到了几个不同的function。接下来在做预测的时候,把数据分别丢进这些模型,然后对结果做平均(对回归问题)或者投票(对分类问题),这就是bagging的思想。

什么时候做bagging?当你的模型很复杂,bias低而variance高,容易过拟合的时候去做bagging。决策树这样的模型就很容易过拟合,所以bagging经常会与决策树一起用。

随机森林

随机森林就是bagging的一个应用。当然仅仅是随机sample是不够的,在每一次随机划选择数据的时候,还需要随机决定使用哪些特征。最后把这些树结合起来就是随机森林。同时注意随机森林在使用时并不需要划分训练集。

Boosting

Boosting是用在弱的基分类器(erro rate小于0.5就可以)上,通过集成弱分类器,可以得到一个效果较好的综合分类器。首先需要找一个分类器 f_1(x) ,然后找另一个分类器 f_2(x) 去帮助 f_1(x) , 当然 f_2(x) 不能和 f_1(x) 太相似。接下来,再寻找第二个 f_2(x) ,最后再把所有的分类器集合起来...在这里注意,boosting的分类器选择是有顺序的,而上面说的bagging是没顺序的。

那么怎么样得到不同的基分类器呢?我们可以通过构造的训练集来训练不同的分类器。除了resample数据,也可以改变每个数据的权重即re-weight,在实际应用中,一般是通过修改损失函数来完成的,对于不同的样本,其损失函数前面会乘上不同的洗漱,比如我们对每一笔数据一个weight u,开始所有的u都是1,我们可以重新赋值u,令不同的数据不一样。现在的一笔数据可以表示为:(x^1, hat{y}, mu^1) ,原来我们的目标函数是: L(f) = sum_nl(f(x^n), hat y^n) ,现在变为 L(f) = sum_n u^nl(f(x^n), hat y^n) 。下面我们看看经典的boosting演算法Adaboost的原理:

Adaboost

Adaboost的意思是,在 f_1(x) 训练不好的数据上训练去训练 f_2(x) , 那么主要问题是, 怎么找到这个 f_1(z) 训练不好的数据集呢?

我们通过计算 f_1(x) 的error rate varepsilon_1 来得到新的数据集

varepsilon_1 = frac{sum_n u_1^nsigma(f_1(x^n)
e hat y^n)}{Z_1} \ Z_1=sum_nmu_1^n

只要基分类器不是随机的,那么 varepsilon_1总会小于 0.5。

接下来,我们将这些data的·权重 mu_1 改为 mu_2 ,使得:

varepsilon_2 = frac{sum_n u_2^nsigma(f_1(x^n)
e hat y^n)}{Z_2} = 0.5\

那么这个操作就好像是说,我们re-weight了数据后, f_1(x) 的表现变差了。

接下来拿这组新的数据去训练 f_2(x) ,那么就是我们刚刚说的在 f_1(x) 上训练不好的数据上训练 f_2(x) 了。

来看个实例。现在有四笔数据,如下图,我们的 f_1(x) 最开始认错了一笔, varepsilon_1 =0.25,之后我们把答错的data 权重调高,答对的权重调低,然后把这组re-weight的data来训练 f_2(x)

图片来自李宏毅老师ensemble课程

我们整理一下过程,实际上Adaboost是这样操作的

如果 x^n 被分类错误,让么令 u_2^n = u_1^nd_1

如果 x^n 被分类正确,让么令 u_2^n = frac{u_1^n}{d_1}

那么 d_1怎么设定呢?我们之前提到说

varepsilon_1 = frac{sum_n u_1^nsigma(f_1(x^n)
e hat y^n)}{Z_1} \ Z_1=sum_nmu_1^n

同时 varepsilon_2 = frac{sum_n u_2^nsigma(f_1(x^n)
e hat y^n)}{Z_2} = 0.5\

u_2 是由 u_1d_1 乘除得到的。那么上式的分母可以改写为:

{sum_n u_1^nsigma(f_1(x^n)
e hat y^n)} = sum_{f_1(x^n)
ehat y^n}u_1^nd_1

分子可以改写为:

Z_2=sum_nu_2^n = sum_{f_1(x^n)
ehat y^n} u_2^n + sum_{f_1(x^n)hat =y^n} u_2^n \ =  sum_{f_1(x^n)
ehat y^n} u_1^n d_1 + sum_{f_1(x^n)hat =y^n} u_1^n/d_1

根据上面两式,我们便可以将 varepsilon_2 的公式化为:

frac{sum_{f_1(x^n)
ehat y^n }u_1^nd_1}{sum_{f_1(x^n)
ehat y^n }u_1^nd_1 + sum_{f_1(x^n)=hat y^n}u_1^n/d_1} = 0.5

我们把上式颠倒过来,在消去分子分母中都包含的项,得到

frac{sum_{f_1(x^n)=hat y^n}u_1^n/d_1}{sum_{f_1(x^n)
ehat y ^n}u_1^nd_1} = 1

也就是说

sum_{f_1(x^n)=hat y^n}u_1^n/d_1 = sum_{f_1(x^n)
ehat y^n}u_1^n/d_1

我们知道,

varepsilon_1 = frac{sum_n u_1^nsigma(f_1(x^n)
e hat y^n)}{Z_1} \ Z_1=sum_nmu_1^n

因此 u_1^n 可以用 varepsilon_1,Z_1 表示,于是,我们可以推出

d_1 = sqrt{(1-varepsilon_1)/varepsilon_1}

根据上面的演算法解释,我们可以列出AdaBoost的流程:

AdaBoost流程

  • 给定训练数据 {(x^1, hat y^1, mu_1^1),...,(x^n, hat y^n, mu_1^n),...,(x^N, hat y^N, mu_1^N)
    • hat y = pm 1, u_1^n=1
  • 对每次epoch t = 1...T:
    • 训练一个基分类器 f_t(x) ,权重记为 {u_t^1,...,u_t^N}
    • varepsilon_t 是 基于{u_t^1,...,u_t^N}f_t(x) 的error rate
    • 对于n=1,...,N:
      • 如果分类错误,那么 u_{t+1}^n = u_t^n *d_t , 反之 u_{t+1}^n = u_t^n /d_td_t = sqrt{(1-varepsilon_t)/varepsilon_t} ,这里我们为了把两种情况合并为一个式子,我们不再使用 d_t ,而使用 alpha_t 作为参数,令 alpha_t = lnsqrt{(1-varepsilon_t)/varepsilon_t} , 则 u_{t+1}^n = u_t^n * exp(-hat y^nf_t(x^n)alpha_t) ,其中 hat y 是真实的分类标签。
    • 现在我们得到了一打基分类器 f_1(x),...,f_t(x),...,f_T(x) ,我们计算 H(x) = sign(sum_{t=1}^Talpha_tf_t(x)) ,相当于说每个分类器乘上一个权重(也就是前面几步中用的 alpha_t ),优秀的基分类器的权重会更大,弱鸡的则会更小。最后计算所有分类器雷加起来的正负值,就可以确定类别。

推荐阅读:

相关文章