zoukankan      html  css  js  c++  java
  • 10.集成学习与随机森林

    1.什么是集成学习

    什么是集成学习,以前我们都是使用一个算法来进行预测,难免会有"独断专行"的感觉。集成学习是将多个算法集成在一块,然后多个算法对同一个问题进行预测,然后少数服从多数,这便是集成学习。

    我们生活中有很多集成学习的例子,比如买东西的时候看推荐,如果10个人推荐你买A产品,但是只有1个人推荐你买B产品,我们会更将倾向于买B产品。

    我们看看sklearn是如何为我们提供集成学习的接口的。

    from sklearn.datasets import make_moons
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import VotingClassifier  # ensemble,与集成学习有关的模块
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=666)
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
    
    from sklearn.linear_model import LogisticRegression
    from sklearn.svm import SVC
    from sklearn.tree import DecisionTreeClassifier
    # 传入一系列分类器,和Pipeline有点像
    voting_clf = VotingClassifier([
        ("log_clf", LogisticRegression()),
        ("svm_clf", SVC()),
        ("dt_clf", DecisionTreeClassifier())
    ], voting="hard")  # voting="hard"表示少数服从多数
    
    voting_clf.fit(X_train, y_train)
    print(voting_clf.score(X_test, y_test))  # 0.888
    

    2.SoftVoting Classifier

    SoftVoting Classifier是什么呢?我们之前说的集成学习使用投票的方式,通过少数服从多数进行选择。但有些时候少数服从多数并不是合理的吗,也就是可能会出现所谓的"民主暴政"。因此更加合理的方式应该是,对于不同的算法来说,所投的票应该是权值的。

    比如经济政策,那么经济学家的建议应该被充分的考虑,或者投的票的权值要大一些。而普通民众,哪怕他是个伟大的航天学家,但与经济无关,所以他的票则不应该被分配较大的权值,这是无可厚非的。

    我们实际举例一下

    我们看到五个模型进行预测,三个模型预测为B的可能性更大一些,所以2vs3,那么最终结果为B。但是我们仔细观察一下,就能发现端倪,预测为A的模型,它们的把握都是非常高的,而预测为B的模型,相对来说把握就不那么高了。所以这样投票是不公平的,你想到了什么,对,最一开始的K近邻,我们也是使用单纯的个数投票,但是没有把距离给考虑进去。集成学习也是一样,如果一个算法特别的有把握,那么它的票的权值理应被分配的大一些。

    如果是Soft Voting的话,那么使用概率的平均值进行考虑,使用五个模型的预测为A的概率相加取平均值,得到0.616,而B时候0.384,因此我们认为分类的结果为A。

    因此使用Softing Voting的话,那么就要求集合中的每一个模型都能估计概率。在逻辑回归中,本身就是基于概率模型进行预测的,有一个predict_proba。而knn显然也是可以的,k取3的话,有两个数据是红色,1个是蓝色,那么是红色的概率就是2/3。决策树也是一样的,走到一个叶子节点,根据训练得到的数据集求出相应的概率。SVM也是可以的,只是会很麻烦,不过sklearn为我们提供好了,只是会牺牲一些计算资源。

    from sklearn.datasets import make_moons
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import VotingClassifier  # ensemble,与集成学习有关的模块
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=666)
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
    
    from sklearn.linear_model import LogisticRegression
    from sklearn.svm import SVC
    from sklearn.tree import DecisionTreeClassifier
    # 传入一系列分类器,和Pipeline有点像
    voting_clf = VotingClassifier([
        ("log_clf", LogisticRegression()),
        ("svm_clf", SVC(probability=True)),  # 默认SVM是不支持预测概率的,如果需要的话,要加上这个参数
        ("dt_clf", DecisionTreeClassifier())
    ], voting="soft")  # voting="soft"表示不是少数服从多数,而是有权值
    
    voting_clf.fit(X_train, y_train)
    print(voting_clf.score(X_test, y_test))  # 0.896
    

    3.Bagging和Pasting

    虽然有很多机器学习的方法,但是从投票的角度看,仍然不够多。因此我们要创建更多的子模型,集成更多的子模型的意见。并且注意,子模型之间不能一致,要求差异性。

    那么如何创建差异性呢?一种办法是每个子模型只看一部分数据,例如有500个样本数据,每个子模型只看100个样本数据,这样即便算法一样,但是由于样本不同,也是会有差异性的。但是这样的话,子模型的预测的准确率不就变低了吗?事实上也是如此,虽然一个子模型的准确率比较低,但是多个子模型组合在一起准确率就变得高了,这也是集成学习的威力。

    那么每个子模型只看样本数据的一部分,那怎么怎么看样本数据的一部分呢?这里也就有了差异,我们有两种方式。

    • Bagging:放回取样
    • Pasting:不放回取样

    Bagging更常用,而且避免了随机所带来的问题,因为每一次都放回取样。

    from sklearn.datasets import make_moons
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import BaggingClassifier
    from sklearn.tree import DecisionTreeClassifier
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=222)
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=222)
    
    bagging_clf = BaggingClassifier(
        DecisionTreeClassifier(), # 传入一个分类器,一般我们都会选择决策树
        n_estimators=500,  # 要创建多少个子模型
        max_samples=100,  # 每一个子模型看多少个样本
        bootstrap=True  # 表示是否放回取样,True表示放回,所以在sklearn中只用一个Bagging,通过控制bootstrap来表示是否放回
    )
    
    bagging_clf.fit(X_train, y_train)
    print(bagging_clf.score(X_test, y_test))  # 0.944
    

    4.oob(out-of-Bag)和关于Bagging的更多讨论

    我们通过有放回的取样的话,那么由于每一次都是从全部的样本中选出一部分样本,那么是有可能有一部分样本是取不到的,经过严格的数学证明,大概是有37%的样本取不到。这37%的样本就叫做out-of-bag,意思是从来没有被取出来。

    既然如此,那么天生就不需要使用train_test_split了,因为有37%的数据是没有见过的,我们直接使用者37%的数据进行测试即可。sklearn也为我们封装一个oob_score_,可以让我们直接查看分数。

    from sklearn.datasets import make_moons
    from sklearn.ensemble import BaggingClassifier
    from sklearn.tree import DecisionTreeClassifier
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=222)
    
    bagging_clf = BaggingClassifier(
        DecisionTreeClassifier(),
        n_estimators=500,
        max_samples=100,
        bootstrap=True,
        oob_score=True  # 加上这个参数表示我们要记录哪些样本被取了,这样后续才能使用那些没有被使用的样本
    )
    
    # 直接传入所有数据进行训练
    bagging_clf.fit(X, y)
    # 这个命名方式也不用说了,表示不是由用户传来的,而是中途生成的,可以调用查看的属性
    print(bagging_clf.oob_score_)  # 0.902
    

    并且Bagging极易使用并行化处理,可以使用n_jobs参数

    我们除了对样本进行采样,每次只看一部分样本,还可以对特征进行采样,即每次只看一部分特征。对于那些特征非常多的样本,比如像素识别,我们就可以使用特征随机采样,通过bootstrap_features=True指定。除此之外,我们既可以针对样本随机采样,也可以针对特征随机采样。

    5.随机森林和Extra-Trees

    我们之前使用集成学习用的模型都是决策树,这些树都是随机的,并且树的数量多了,就变成了什么呢?对,所以有一个更形象的说法,叫随机森林。

    并且sklearn已经为我们封装了随机森林这个算法

    from sklearn.datasets import make_moons
    from sklearn.ensemble import RandomForestClassifier
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=666)
    
    rf_clf = RandomForestClassifier(n_estimators=500,  # 多少颗决策树
                                    random_state=666,  # 树是随机的
                                    oob_score=True,
                                    n_jobs=-1
                                    )
    # 直接传入所有数据进行训练
    rf_clf.fit(X, y)
    # 这个命名方式也不用说了,表示不是由用户传来的,而是中途生成的,可以调用查看的属性
    print(rf_clf.oob_score_)  # 0.892
    

    除了随机森林,还有一个Extra-Trees,意思是极其随机数,数是复数,表示有很多数。在决策树的节点划分上,使用了随机的特征和随机的阈值。提供了额外的随机性,抑制过拟合,但增大了bias。

    from sklearn.datasets import make_moons
    from sklearn.ensemble import ExtraTreesClassifier
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=666)
    
    rf_clf = ExtraTreesClassifier(n_estimators=500,  # 多少颗决策树
                                  random_state=666,  # 树是随机的
                                  oob_score=True,
                                  bootstrap=True,
                                  n_jobs=-1
                                  )
    rf_clf.fit(X, y)
    print(rf_clf.oob_score_)  # 0.892
    

    当然除了分类问题,也可以解决回归问题。

    6.Ada Boosting和Gradient Boosting

    Boosting,继承多个模型,每个模型都在尝试增强(Boosting)整体的效果。举个栗子

    这是一个Ada Boosting,首先我们进行预测,必然会有犯错误的点,那么将没有很好预测的点做标记,变成的新的数据,所以看到蓝色的点加深了的,表示上一个模型没有很好预测的数据,然后新的模型会继续预测,对于上一个模型没有预测好的数据,相应的权值会增加。那么既然是预测,就总会犯错误,然后后续的继续重复相同的动作。因此每一个模型都在不断增强整体的效果,这就是Ada  Boosting

    我们看看sklearn中的Ada Boosting

    from sklearn.datasets import make_moons
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import AdaBoostClassifier
    from sklearn.tree import DecisionTreeClassifier
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=666)
    
    ada_clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2),
                                n_estimators=500
                                )
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
    ada_clf.fit(X_train, y_train)
    
    print(ada_clf.score(X_test, y_test))  # 0.864
    

    Gradient Boosting的原理是,训练一个模型,产生错误e1,针对e1进行训练,产生错误e2,针对e2训练,产生错误e3,最终预测结果:m1+m2+m3+······,所以说每次训练都是对前一次失误进行补偿。

    from sklearn.datasets import make_moons
    from sklearn.model_selection import train_test_split
    from sklearn.ensemble import GradientBoostingClassifier
    
    X, y = make_moons(n_samples=500, noise=0.3, random_state=666)
    
    gb_clf = GradientBoostingClassifier(max_depth=2,  # 这里不需要指定分类器,默认是以决策树作为基础的
                                         n_estimators=500
                                         )
    X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
    gb_clf.fit(X_train, y_train)
    
    print(gb_clf.score(X_test, y_test))  # 0.896
    

    这些集成算法都可以解决回归问题

    7.Stacking

    还记得之前的Voting Classifier吗?多个算法进行预测,预测出多个结果,然后对这三个结果进行综合得到结果。但是Stacking不一样,它没有直接对三个结果进行综合,而是用这个三个结果作为输入,再添加一层,预测出结果,这便是Stacking。同样Stacking既可以解决分类问题,也可以解决回归问题。

    如果再复杂一些的话,我们可以分为三层。这就意味着我们需要把数据集分成三份,第一份训练第一层,第二份训练第二层,第三份训练第三层。其实看到这里就有点像是神经网络了,关于Stacking,sklearn没有提供相应的模型让我们使用,有兴趣的话可以自己实现一下。

  • 相关阅读:
    Golang的值类型和引用类型的范围、存储区域、区别
    ubuntu下ssh使用 与 SCP 使用
    ubuntu 搭建svn服务器
    Java中Math类的几个四舍五入方法的区别
    mongoDB 批量更改数据,某个字段值等于另一个字段值
    mongoDB 查询附近的人的语句
    mongodb常用操作语句
    JAVA 根据经纬度算出附近的正方形的四个角的经纬度
    JAVA 计算地球上任意两点(经纬度)距离
    Mongodb数据备份恢复
  • 原文地址:https://www.cnblogs.com/traditional/p/11524945.html
Copyright © 2011-2022 走看看