机器学习----深入解剖随机森林算法

老少爷们呦~更多精彩解析尽在小樱的总目录页,点击这里呦~


              其实从直观角度来解释,每棵决策树都是一个分类器(假设现在针对的是分类问题),那么对于一个输入样本,N棵树会有N个分类结果。而随机森林集成了所有的分类投票结果,将投票次数最多的类别指定为最终的输出,这就是一种最简单的 Bagging 思想

1123

一. 随机森林使用背景


1.1、 随机森林历史

                随机森林是一种比较新的机器学习模型。经典的机器学习模型是神经网络,有半个多世纪的历史了。神经网络预测精确,但是计算量很大。上世纪八十年代Breiman等人发明分类树的算法(Breiman et al. 1984),通过反复二分数据进行分类或回归,计算量大大降低。2001年Breiman把分类树组合成随机森林(Breiman 2001a),即在变量(列)的使用和数据(行)的使用上进行随机化,生成很多分类树,再汇总分类树的结果。随机森林在运算量没有显著提高的前提下提高了预测精度。随机森林对多元共线性不敏感,结果对缺失数据和非平衡的数据比较稳健,可以很好地预测多达几千个解释变量的作用(Breiman 2001b),被誉为当前最好的算法之一(Iverson et al. 2008)。


1.2、什么是随机森林

                随机森林顾名思义,是用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的(跟Adaboost相反,Adaboost的每个基学习器互相相关)。在得到森林之后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类(对于分类算法),然后看看哪一类被选择最多,就预测这个样本为那一类。


1.3、随机森林有什么优点

随机森林是一个最近比较火的算法,它有很多的优点:

                ● 在数据集上表现良好
                ● 在在当前的很多数据集上,相对其他算法有着很大的优势
                ● 在它能够处理很高维度(feature很多)的数据,并且不用做特征选择
                ● 在在训练完后,它能够给出哪些feature比较重要
                ● 在在创建随机森林的时候,对generlization error(全局错误率)使用的是无偏估计
                ● 在训练速度快
                ● 在在训练过程中,能够检测到feature间的互相影响
                ● 在容易做成并行化方法
                ● 在实现比较简单

无偏估计的解释:

                比如我要对某个学校一个年级的上千个学生估计他们的平均水平(真实值,上帝才知道的数字),那么我决定抽样来计算。我抽出一个10个人的样本,可以计算出一个均值。那么如果我下次重新抽样,抽到的10个人可能就不一样了,那么这个从样本里面计算出来的均值可能就变了,对不对?因为这个均值是随着我抽样变化的,而我抽出哪10个人来计算这个数字是随机的,那么这个均值也是随机的。但是这个均值也会服从一个规律(一个分布),那就是如果我抽很多次样本,计算出很多个这样的均值,这么多均值们的平均数应该接近上帝才知道的真实平均水平。如果你能理解“样本均值”其实也是一个随机变量,那么就可以理解为这个随机变量的期望是真实值,所以无偏(这是无偏的定义);而它又是一个随机变量,只是估计而不精确地等于,所以是无偏估计量。

详情链接:https://www.zhihu.com/question/22983179/answer/23470969


二、原理解剖

2.1、算法原理—-决策树

                决策树(decision tree)是一个树结构(可以是二叉树或非二叉树)。其每个非叶节点表示一个特征属性上的测试,每个分支代表这个特征属性在某个值域上的输出,而每个叶节点存放一个类别。使用决策树进行决策的过程就是从根节点开始,测试待分类项中相应的特征属性,并按照其值选择输出分支,直到到达叶子节点,将叶子节点存放的类别作为决策结果。

                随机森林是用随机的方式建立一个森林,森林里面有很多的决策树组成,随机森林的每一棵决策树之间是没有关联的。在得到森林之后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类,然后看看哪一类被选择最多,就预测这个样本为那一类。


这里就不做过多的解释,关于决策树,做了单独的解释算法原理解释和计算链接如下:
https://blog.csdn.net/Sakura55/article/details/80786499


2.2、采样原理—-bootstrap自助式采样

                它通过自助法(bootstrap)重采样技术从原始训练样本集N中有放回地重复随机抽取k个样本生成新的训练样本集合,然后根据自助样本集生成k个分类树组成随机森林,新数据的分类结果按分类树投票多少形成的分数而定。其实质是对决策树算法的一种改进,将多个决策树合并在一起,每棵树的建立依赖于一个独立抽取的样品,森林中的每棵树具有相同的分布,分类误差取决于每一棵树的分类能力和它们之间的相关性。特征选择采用随机的方法去分裂每一个节点,然后比较不同情况下产生的误差。能够检测到的内在估计误差、分类能力和相关性决定选择特征的数目。单棵树的分类能力可能很小,但在随机产生大量的决策树后,一个测试样品可以通过每一棵树的分类结果经统计后选择最可能的分类。


2.3、带外错误率—-oob估计

              在构建每棵树时,我们对训练集使用了不同的bootstrap sample(随机且有放回地抽取)所以对于每棵树而言(假设对于第k棵树),大约有1/3的训练实例没有参与第k棵树的生成,它们称为第k棵树的oob样本。

  而这样的采样特点就允许我们进行oob估计,它的计算方式如下:

  (note:以样本为单位)

  1)对每个样本,计算它作为oob样本的树对它的分类情况(约1/3的树);

  2)然后以简单多数投票作为该样本的分类结果;

  3)最后用误分个数占样本总数的比率作为随机森林的oob误分率。

oob误分率是随机森林泛化误差的一个无偏估计,它的结果近似于需要大量计算的k折交叉验证。


2.4、随机森林构造过程

2.2.4随机森林实现过程

              随机森林中的每一棵分类树为二叉树,其生成遵循自顶向下的递归分裂原则,即从根节点开始依次对训练集进行划分;在二叉树中,根节点包含全部训练数据, 按照节点纯度最小原则,分裂为左节点和右节点,它们分别包含训练数据的一个子集,按照同样的规则节点继续分裂,直到满足分支停止规则而停止生长。若节点n上的分类数据全部来自于同一类别,则此节点的纯度I(n)=0,

纯度度量方法是Gini准则,即假设P(Xj)是节点n上属于Xj 类样本个数占训练。

具体实现过程如下:

(1)原始训练集为N,应用bootstrap法有放回地随机抽取k个新的自助样本集,并由此构建k棵分类树,每次未被抽到的样本组成了k个袋外数据;

(2)设有mall个变量,则在每一棵树的每个节点处随机抽取mtry个变量(mtry n mall),然后在mtry中选择一个最具有分类能力的变量,变量分类的阈值通过检查每一个分类点确定;

(3)每棵树最大限度地生长, 不做任何修剪;

(4)将生成的多棵分类树组成随机森林,用随机森林分类器对新的数据进行判别与分类,分类结果按树分类器的投票多少而定


三 、随机森林应用范围

                随机森林主要应用于回归和分类。本文主要探讨基于随机森林的分类问题。随机森林和使用决策树作为基本分类器的(bagging)有些类似。以决策树为基本模型的bagging在每次bootstrap放回抽样之后,产生一棵决策树,抽多少样本就生成多少棵树,在生成这些树的时候没有进行更多的干预。而随机森林也是进行bootstrap抽样,但它与bagging的区别是:在生成每棵树的时候,每个节点变量都仅仅在随机选出的少数变量中产生。因此,不但样本是随机的,连每个节点变量(Features)的产生都是随机的。

                许多研究表明, 组合分类器比单一分类器的分类效果好,随机森林(random forest)是一种利用多个分类树对数据进行判别与分类的方法,它在对数据进行分类的同时,还可以给出各个变量(基因)的重要性评分,评估各个变量在分类中所起的作用。


3.1、分类

                随机森林也很善长分类问题。它可以被用于为多个可能目标类别做预测,它也可以在调整后输出概率。你需要注意的一件事情是过拟合。

                随机森林容易产生过拟合,特别是在数据集相对小的时候。当你的模型对于测试集合做出“太好”的预测的时候就应该怀疑一下了。避免过拟合的一个方法是在模型中只使用有相关性的特征,比如使用之前提到的特征选择。
123

3.2、回归

                  随机森林是一个简单的决策树的集合,输入向量在多个决策树上运行。对于回归问题,所有决策树的输出值都是平均的;对于分类问题,使用一个投票方案来确定最终的类别。


3.3、简单案例

描述:根据已有的训练集已经生成了对应的随机森林,随机森林如何利用某一个人的年龄(Age)、性别(Gender)、教育情况(Highest Educational Qualification)、工作领域(Industry)以及住宅地(Residence)共5个字段来预测他的收入层次。

  收入层次 :

    Band 1 : Below $40,000

    Band 2: $40,000 – 150,000

    Band 3: More than $150,000

  随机森林中每一棵树都可以看做是一棵CART(分类回归树),这里假设森林中有5棵CART树,总特征个数N=5,我们取m=1(这里假设每个CART树对应一个不同的特征)。

这里写图片描述

我们要预测的某个人的信息如下:

  1. Age : 35 years ; 2. Gender : Male ; 3. Highest Educational Qualification : Diploma holder; 4. Industry : Manufacturing; 5. Residence : Metro.

  根据这五棵CART树的分类结果,我们可以针对这个人的信息建立收入层次的分布情况:
这里写图片描述

最后,我们得出结论,这个人的收入层次70%是一等,大约24%为二等,6%为三等,所以最终认定该人属于一等收入层次(小于$40,000)。


随即森林Python实现的代码


'''
    随机森林
    离散属性
    1、基学习器深度取为1 ,因为我这里
       只随机取1个进行决策树分析,
       没有用到CART决策树,按gini系数比较。对特征多的可以加上。
       ps:要对每个基学习器的节点随机抽取一个特征进行分叉,除非像我一样
       ,将每棵树的高度设为1.
    2、基学习器可以并行生成,有兴趣的可以用Threading或multiprocessing模块
       来实现,还是不太难的。这里没有写出
'''
# from sklearn.ensemble import RandomForestClassifier
import numpy as np
import pandas as pd
import random
from threading import Thread
from collections import Counter


def xunlian(data, number):
    featureChoice = int(np.random.randint(0, number-1, 1))
    features = list(data[featureChoice].unique())
    # features为['清脆', '沉闷']的形式

    categorys = list(data[featureChoice])
    dicts = {}
    cc = 0

    for ll in features:
        dicts[ll] = []


    for m in categorys:
        for j in features:
            if m == j:
                dicts[j].append(cc)
                cc += 1

    for i in features:
        lst = dicts.get(i)
        new_lst = []
        if len(lst) > 0:
            for k in lst:
                new_lst.append(int(data[k:k+1][data.shape[1]-1]))
            jieguo = Counter(new_lst).most_common(1)[0][0]
            dicts[i] = jieguo

    return dicts
    # dicts 为 {'清脆':1, '沉闷':0}的形式


class RandomForest():

    def __init__(self, n_estimators = 3):
        self.estimators = n_estimators

    @staticmethod
    def assemble(inputs, labels):
        n = len(labels)
        for i in range(n):
            inputs[i].append(labels[i])

        data = np.vstack(inputs)
        return data

    def train(self, inputs, labels):
        n = len(inputs[0])  # 特征个数
        data = RandomForest.assemble(inputs, labels)
        data = pd.DataFrame(data)

        sum_dicts = {}

        rows = int(data.shape[0])
        rcounts = rows - 1

        for i in range(self.estimators):
            df = pd.DataFrame()
            for m in range(rows):
                j = random.randint(0, int(rcounts))
                df = df.append(data.loc[j, :])
            sum_dicts[i] = xunlian(df, n)

        return sum_dicts
        # 多线程并行生成基学习器方式:以后有时间完善
        # threads = []
        # for i in range(self.estimators):
        #     ti = Thread(target=xunlian, args=(data, n,))
        #     threads.append(ti)
        #
        # for t in threads:
        #     t.setDeamon(True)
        #     t.start()


    def predict(self, input, model):
        n = len(model)
        # n为基学习器的个数
        predicts = list()
        for i in range(n):
            categoryes = model[i]
            for j in input:
                if j in categoryes.keys():
                    predicts.append(categoryes[j])
        prediction = Counter(predicts).most_common(1)
        print(prediction)
        if prediction[0][0] == 0:

            print("预测结果为:坏瓜")
        else:

            print("预测结果为:好瓜")


if __name__ == "__main__":
    ex = RandomForest()  # 默认为3个基学习器
    a0 = ['浅绿', '清脆', '中']
    a1 = ['深绿', '沉闷', '大']
    a2 = ['薄白', '清脆', '小']
    a3 = ['浅绿', '清脆', '小']
    a4 = ['深绿', '沉闷', '中']
    lst = [a0, a1, a2, a3, a4]
    y = [0, 1, 0, 1, 1]  ################# 0坏 1好

    model = ex.train(lst, y)

参考:
                            https://blog.csdn.net/nieson2012/article/details/51279332
                            https://blog.csdn.net/nongfu_spring/article/details/39644859

猜你喜欢

转载自blog.csdn.net/Sakura55/article/details/81413036