美文网首页
集成学习(7) - 集成学习之投票法原理与案例分析

集成学习(7) - 集成学习之投票法原理与案例分析

作者: 木头里有虫911 | 来源:发表于2021-04-14 21:22 被阅读0次

    1. 投票法简介

    在之前的学习,我们了解到一个通过数据学习得来的算法模型在实际预测中,存在两种误差,即方差和偏差。其中偏差是指预测值和实际值的差值;方差是指模型在同一分布的不同数据集上的扰动,即由于样本数据不同而带来的误差。
    而我们不断开发新的机器学习算法开发目的就是寻找方法来降低这些误差。

    而投票法就是这样的方法,它是集成学习中常用的技巧,可以帮助我们提高模型的泛化能力,减少模型的错误率。
    这也符合我们经常听到的所谓兼听则明的思想。集思广益大部分时候可以获得比单个个体的想法更好,这个是投票法朴素的解释。

    投票法在回归模型与分类模型上均可使用:

    • 回归投票法:预测结果是所有模型预测结果的平均值。
    • 分类投票法:预测结果是所有模型种出现最多的预测结果。

    分类投票法又可以被划分为硬投票与软投票:

    • 硬投票:预测结果是所有投票结果最多出现的类。
    • 软投票:预测结果是所有投票结果中概率加和最大的类。

    2. 投票法的原理分析

    投票法是一种遵循少数服从多数原则的集成学习模型,通过多个模型的集成降低方差,从而提高模型的鲁棒性。
    在理想情况下,投票法的预测效果应当优于任何一个基模型的预测效果。

    下面我们使用一个例子说明硬投票:

    对于某个样本:

    模型 1 的预测结果是 类别 A
    模型 2 的预测结果是 类别 B
    模型 3 的预测结果是 类别 B

    有2/3的模型预测结果是B,因此硬投票法的预测结果是B

    同样的例子说明软投票:

    对于某个样本:
    模型 1 的预测结果是 类别 A 的概率为 99%
    模型 2 的预测结果是 类别 A 的概率为 49%
    模型 3 的预测结果是 类别 A 的概率为 49%

    最终对于类别A的预测概率的平均是 (99 + 49 + 49) / 3 = 65.67%,因此软投票法的预测结果是A。

    从这个例子我们可以看出,软投票法与硬投票法可以得出完全不同的结论。相对于硬投票,软投票法考虑到了预测概率这一额外的信息,
    因此可以得出比硬投票法更加准确的预测结果。

    在投票法中,我们还需要考虑到不同的基模型可能产生的影响。理论上,基模型可以是任何已被训练好的模型。
    但在实际应用上,想要投票法产生较好的结果,需要满足两个条件:

    • 基模型之间的效果不能差别过大。当某个基模型相对于其他基模型效果过差时,该模型很可能成为噪声。
    • 基模型之间应该有较小的同质性。例如在基模型预测效果近似的情况下,基于树模型与线性模型的投票,往往优于两个树模型或两个线性模型。

    3. 算法实现

    1. 手动实现,不使用sklearn中封装好的算法:
      我们首先手动实现硬投票法实现分类问题,我们使用葡萄酒数据集,并使用KNN,决策树和LR模型
      1.1 导入数据集,以及相应的算法模型:
    import pandas as pd
    import numpy as np
    
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.linear_model import LogisticRegression
    
    from sklearn import datasets
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import accuracy_score
    

    导入数据集,并拆分为训练集和测试集

    # 加葡萄酒据集
    wine = datasets.load_wine()
    X, y = wine.data, wine.target
    X_train, X_test, y_train, y_test = train_test_split(X, y , test_size = 0.3)
    
    print(X_train.shape, y_train.shape)
    print(X_test.shape, y_test.shape)
    
    print(X[:5], y[:5])
    >>>
    (124, 13) (124,)
    (54, 13) (54,)
    [[1.423e+01 1.710e+00 2.430e+00 1.560e+01 1.270e+02 2.800e+00 3.060e+00
      2.800e-01 2.290e+00 5.640e+00 1.040e+00 3.920e+00 1.065e+03]
     [1.320e+01 1.780e+00 2.140e+00 1.120e+01 1.000e+02 2.650e+00 2.760e+00
      2.600e-01 1.280e+00 4.380e+00 1.050e+00 3.400e+00 1.050e+03]
     [1.316e+01 2.360e+00 2.670e+00 1.860e+01 1.010e+02 2.800e+00 3.240e+00
      3.000e-01 2.810e+00 5.680e+00 1.030e+00 3.170e+00 1.185e+03]
     [1.437e+01 1.950e+00 2.500e+00 1.680e+01 1.130e+02 3.850e+00 3.490e+00
      2.400e-01 2.180e+00 7.800e+00 8.600e-01 3.450e+00 1.480e+03]
     [1.324e+01 2.590e+00 2.870e+00 2.100e+01 1.180e+02 2.800e+00 2.690e+00
      3.900e-01 1.820e+00 4.320e+00 1.040e+00 2.930e+00 7.350e+02]] [0 0 0 0 0]
    

    1.2 创建模型并输出预测结果精度

    knn = KNeighborsClassifier(n_neighbors= 2)
    dt = DecisionTreeClassifier(max_depth=2)
    lr = LogisticRegression(tol= 0.1, random_state= 10, solver='lbfgs')
    
    for mod in [knn, dt, lr]:
        mod.fit(X_train, y_train)
        y_predict = mod.predict(X_test)
        mod_score = accuracy_score(y_test, y_predict)
        print('using modle {}, the accury is {:.3f}'.format(mod, mod_score))
    >>>
    using modle KNeighborsClassifier(n_neighbors=2), the accury is 0.648
    using modle DecisionTreeClassifier(max_depth=2), the accury is 0.889
    using modle LogisticRegression(random_state=10, tol=0.1), the accury is 0.944
    

    1.3 下面手动实现hard voting 即硬投票

    我们首先打印出上面三个算法的预测结果,打印前20个

    knn.fit(X_train, y_train)
    y_knn = knn.predict(X_test)
    print(y_knn[:20])
    
    dt.fit(X_train, y_train)
    y_dt = dt.predict(X_test)
    print(y_dt[:20])
    
    lr.fit(X_train, y_train)
    y_lr = lr.predict(X_test)
    print(y_lr[:20])
    >>>
    [0 2 1 2 1 0 1 1 1 0 0 2 2 2 0 0 1 0 1 1]
    [1 0 1 2 2 1 1 2 1 0 2 1 1 2 0 0 1 0 1 2]
    [1 1 1 2 2 1 1 2 1 0 0 1 1 2 0 0 1 0 1 2]
    

    下面使用投票法结合三者

    hard_predict = []
    for i in range(y_test.shape[0]):
        counts = [0 for _ in range(2)] #二分类,先初始化两个类别的票数均为0
        counts[y_knn[i]] += 1
        counts[y_dt[i]] += 1
        counts[y_lr[i]] += 1
        
        # get the max valve with hard voting for final predictions
        final = np.argmax(counts)
        
        hard_predict.append(final)
        
    print(hard_predict[:20])
    >>>
    [1, 0, 1, 2, 2, 1, 1, 2, 1, 0, 0, 1, 1, 2, 0, 0, 1, 0, 1, 2]
    使用voting算法的默认参数获得的正确率为: 0.926
    

    对比集成的结果和上面3个模型的预测,可以明显的看到精度的提升。

    1. 在sklearn的ensemble 模块中也封装了 VotingClassifier用于分类可以直接调用
      下面我们使用一个完整的例子演示投票法的使用:

    首先我们创建一个1000个样本,20个特征的随机数据集:

    from sklearn.datasets import make_classification
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.model_selection import RepeatedStratifiedKFold
    from sklearn.model_selection import cross_val_score
    import matplotlib.pyplot as plt
    plt.style.use('bmh')
    
    from sklearn.ensemble import VotingClassifier
    from sklearn.datasets import make_classification
    # define dataset
    X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=2)
    # summarize the dataset
    print(X.shape, y.shape)
    >>>(1000, 20) (1000,)
    

    2.2 我们使用多个KNN模型作为基模型演示投票法,其中每个模型采用不同的邻居值K参数:

    # get a voting ensemble of models
    def get_voting():
        # define the base models
        models = list()
        models.append(('knn1', KNeighborsClassifier(n_neighbors=1)))
        models.append(('knn3', KNeighborsClassifier(n_neighbors=3)))
        models.append(('knn5', KNeighborsClassifier(n_neighbors=5)))
        models.append(('knn7', KNeighborsClassifier(n_neighbors=7)))
        models.append(('knn9', KNeighborsClassifier(n_neighbors=9)))
    # define the voting ensemble
        ensemble = VotingClassifier(estimators=models, voting='hard')
        return ensemble
    

    """
    2.3 创建一个模型列表来评估投票带来的提升,
    包括KNN模型配置的每个独立版本和硬投票模型。
    下面的get_models()函数可以为我们创建模型列表进行评估。

    # get a list of models to evaluate
    def get_models():
        models = dict()
        models['knn1'] = KNeighborsClassifier(n_neighbors=1)
        models['knn3'] = KNeighborsClassifier(n_neighbors=3)
        models['knn5'] = KNeighborsClassifier(n_neighbors=5)
        models['knn7'] = KNeighborsClassifier(n_neighbors=7) 
        models['knn9'] = KNeighborsClassifier(n_neighbors=9)
        models['hard_voting'] = get_voting()
        return models
    
    # 下面的evaluate_model()函数接收一个模型实例,并以分层10倍交叉验证三次重复的分数列表的形式返回。
    # evaluate a give model using cross-validation
    def evaluate_model(model, X, y):
        cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
        scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
        return scores
    

    2.4 报告每个算法的平均性能,还可以创建一个箱形图和须状图来比较每个算法的精度分数分布。

    models = get_models()
    # evaluate the models and store results
    results, names = list(), list()
    for name, model in models.items():
        scores = evaluate_model(model, X, y)
        results.append(scores)
        names.append(name)
        print('>%s %.3f (%.3f)' % (name, np.mean(scores), np.std(scores)))
    # plot model performance for comparison
    plt.boxplot(results, labels=names, showmeans=True)
    plt.show()
    
    image.png

    本文结

    参考:
    Datawhale开源项目:机器学习集成学习与模型融合(基于python)
    作者: 李祖贤,陈琰钰,赵可,杨毅远,薛传雨

    相关文章

      网友评论

          本文标题:集成学习(7) - 集成学习之投票法原理与案例分析

          本文链接:https://www.haomeiwen.com/subject/sigclltx.html