一、随机森林是什么

随机森林就是通过集成学习的方法将多颗决策树集成的一种算法。每一颗决策树都是一个分类器,对于每一个输入样本,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算法提供的是框架
  • 不用做特征筛选
  • 不用担心过拟合

打赏

发表评论

电子邮件地址不会被公开。