机器学习之-随机森林和adaboost
目录
一、随机森林是什么
随机森林就是通过集成学习的方法将多颗决策树集成的一种算法。每一颗决策树都是一个分类器,对于每一个输入样本,N棵决策树会有N个分类结果。而随机森林集成了所有的分类投票结果,将投票次数最多的类别指定为最终的输出。可见,这也是一种Bagging思想。同时,我们也会讲解Adaboost算法的原理和代码实现。
二、随机森林的优缺点
随机森林有如下优点:
- 在当前所有算法中,具有极好的准确率
- 能够运行在大数据集上
- 能够处理具有高维特征的样本输入,不需要降维
- 能评估哥哥特征在分类问题上的重要性
- 对于缺省值问题,也能够获得好的结果
随机森林的缺点如下:
- 随机森林对于分类工作表现得很好,但是对于回归问题则表现一般,因为它无法给出一个精确连续的预测值
- 随机森林就像一个黑盒,你很难控制它,只能通过尝试不同通的参数来调整,也就是说失去了解释性
二、随机森林如何工作
随机森林的是通过一个个弱的分类器(决策树)最终组成一个强分类器,那么森林中的每棵树是如何生成的呢?
(1)假设训练集大小为N,采用Bootstrap sample的方法,对每棵树,随机有放回地从训练集中抽取N个训练样本,作为该棵树的训练集;
备注:每棵树的训练集都是不同的,而且里面可能包含重复的训练样本
(2)假设每个样本的特征维度为M,制定一个常熟m<<M,随机地从M个特征中选取m个特征子集,每次树进行分裂时,从这m个特征中选择最优的
(3)每棵树都尽最大程度地生长,不进行剪枝
(4)预测新的样本时,只需要将N棵决策树的分类结果合并输出
三、影响随机森林分类效果的因素
- 森林中任意两棵树的相关性:相关性越大,错误率越大
- 森林中每棵树的分类能力:每棵树分类能力越强,整个森林的错误率越低
减少特征m的个数,树的相关行和分类能力都会相应下降;增大m,两者也会随之增大。所以随机森林的一个关键问题就是如何选择最优的m,这也是随机森林唯一的一个参数。
四、Adaboost算法
4.1 Adaboost算法原理
假设给一定一个二类分类的训练数据集
其中,每个样本点由实例与标记组成,实例,标记
,χ是实例空间,γ是标记集合。Adaboost利用以下算法,从训练数据中学习一些列弱分类器或基本分类器,并将这些弱分类器线性组合成一个强分类器。
- 输入:训练数据集
,其中
,
;若学习算法;
- 输出:最终分类器G(x)
- Step1:初始化训练数据的权值分布
- Step2:对m=1,2,...,M
- (a)使用具有权值分布Dm的训练数据集学习,得到基本分类器
- (b)计算Gm(x)在训练数据集上的分类误差率
- (c)计算Gm(x)的系数
这里的对数是自然对数
- (d)更新训练数据集的权值分布
这里,Zm是规范化因子
它使Dm+1是成为一个概率分布。
重要:这里,被基本分类器Gm(x)误分类样本的权值在下一轮中得以扩大,而被正确分类样本的权值就缩小。,所以误分类样本在下一轮学习中起更大的作用。不改变所给的训练数据,而不断改变训练数据权值的分布,使得训练数据在基本分类器的学习中起不同的作用,这也是Adaboost的一个特点。
- Step3:构建基本分类器的线性组合
得到最终能分类器G(x)。
下面,我们通过一个简单的划分坐标点的示例来说明下Adaboost原理:
下面给出一个数据集合,+和-表示两类,下面我们要做的就是通过寻找直线方程来将两类坐标点区分开来。
按照Adaboost算法的思想,我们需要找一系列的简单直线方程来组合划分这些坐标点。
通过Round1、2、3三次迭代,我们分别找到了3个基本分类器,h1、h2和h3。而每一轮中被误分类的样本在下一轮中权值变大(如图中图形变大),而正确分类的样本权值变小(如图中图形变小)。在每一轮学习中,可以得到基本分类器的误差率和系数。
最终,我们将这3个基本分类器通过系数组合成一个强分类器,从而得到最终的分类器G(x)。
4.3 Adaboost算法python代码实现
首先,我们通过make_hastie_10_2方法产生有10个维度的二元分类器数据集。并使用决策树作为基本分类器,通过Adaboost算法框架进行训练学习。
# coding: utf-8 import pandas as pd import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.cross_validation import train_test_split from sklearn.datasets import make_hastie_10_2 import matplotlib.pyplot as plt def get_error_rate(pred, Y): return sum(pred != Y) / float(len(Y)) def print_error_rate(err): print 'Error rate: Training: %.4f - Test: %.4f' % err def generic_clf(Y_train, X_train, Y_test, X_test, clf): clf.fit(X_train, Y_train) pred_train = clf.predict(X_train) pred_test = clf.predict(X_test) return get_error_rate(pred_train, Y_train), \ get_error_rate(pred_test, Y_test) def adaboost_clf(Y_train, X_train, Y_test, X_test, M, clf): n_train, n_test = len(X_train), len(X_test) # 初始化权值 w = np.ones(n_train) / n_train pred_train, pred_test = [np.zeros(n_train), np.zeros(n_test)] for i in range(M): # Fit a classifier with the specific weights clf.fit(X_train, Y_train, sample_weight=w) pred_train_i = clf.predict(X_train) pred_test_i = clf.predict(X_test) # Indicator function miss = [int(x) for x in (pred_train_i != Y_train)] # Equivalent with 1/-1 to update weights miss2 = [x if x == 1 else -1 for x in miss] # 该弱分类器在分布Dt上的Error(误差),即e = P(Ht(xi) != yi) err_m = np.dot(w, miss) / sum(w) # 该弱分类器在最终分类器中所占的权重Alpha, alpha = 1/2 * ln[(1-et)/et] alpha_m = 0.5 * np.log((1 - err_m) / float(err_m)) # New weights,更新训练样本的权值分布Dt+1 w = np.multiply(w, np.exp([float(x) * alpha_m for x in miss2])) # Add to prediction 最后,按弱分类器权重alpha_m组合各个弱分类器,即 # f(x) = Σa * Ht(x) pred_train = [sum(x) for x in zip(pred_train, [x * alpha_m for x in pred_train_i])] pred_test = [sum(x) for x in zip(pred_test, [x * alpha_m for x in pred_test_i])] pred_train, pred_test = np.sign(pred_train), np.sign(pred_test) # Return error rate in train and test set return get_error_rate(pred_train, Y_train), \ get_error_rate(pred_test, Y_test) def plot_error_rate(er_train, er_test): df_error = pd.DataFrame([er_train, er_test]).T df_error.columns = ['Training', 'Test'] plot1 = df_error.plot(linewidth=3, figsize=(8, 6), color=['lightblue', 'darkblue'], grid=True) plot1.set_xlabel('Number of iterations', fontsize=12) plot1.set_xticklabels(range(0, 450, 50)) plot1.set_ylabel('Error rate', fontsize=12) plot1.set_title('Error rate vs number of iterations', fontsize=16) plt.axhline(y=er_test[0], linewidth=1, color='red', ls='dashed') plt.show() if __name__ == '__main__': # 产生有10个维度的二元分类器数据集 x, y = make_hastie_10_2() df = pd.DataFrame(x) df['Y'] = y # 划分成训练集和测试集 train, test = train_test_split(df, test_size=0.2) X_train, Y_train = train.ix[:, :-1], train.ix[:, -1] X_test, Y_test = test.ix[:, :-1], test.ix[:, -1] # 使用决策树作为基本分类器 clf_tree = DecisionTreeClassifier(max_depth=1, random_state=1) er_tree = generic_clf(Y_train, X_train, Y_test, X_test, clf_tree) # 迭代学习 er_train, er_test = [er_tree[0]], [er_tree[1]] x_range = range(10, 410, 10) for i in x_range: er_i = adaboost_clf(Y_train, X_train, Y_test, X_test, i, clf_tree) er_train.append(er_i[0]) er_test.append(er_i[1]) # 错误率和迭代次数关系图 plot_error_rate(er_train, er_test)
最终,我们得到错误率和迭代次数关系图如下:
4.4 Adaboost算法优点
Adaboost算法优点很多,主要有以下:
- Adaboost是一种有很高精度的分类器
- 可以使用各种方法构建子分类器,Adaboost算法提供的是框架
- 不用做特征筛选
- 不用担心过拟合