转载声明
原文作者:Datawhale学习社区
原文链接:Datawhale学习社区
著作权归作者所有,任何形式的转载都请联系作者。
投票法的原理分析
集成学习就是要发挥集体决策的优势,以单个分类模型的分类结果为基础,采用少数服从多数的原则确定模型预测的类别标签。通过多个模型的集成降低方差,从而提高模型的准确性。在理想情况下,投票法的预测效果应当优于任何一个基模型的预测效果。
降低方差对偏差有什么影响??
投票法在回归模型与分类模型上均可使用:
- 回归投票法:预测结果是所有模型预测结果的平均值。
- 分类投票法:预测结果是所有模型种出现最多的预测结果。
分类投票法又可以被划分为硬投票与软投票:
- 硬投票:预测结果是所有投票结果最多出现的类。
- 软投票:预测结果是所有投票结果中概率加和最大的类。
投票法的注意事项
基模型之间的效果不能差别过大。当某个基模型相对于其他基模型效果过差时,该模型很可能成为噪声。
基模型之间应该有较小的同质性。例如在基模型预测效果近似的情况下,基于树模型与线性模型的投票,往往优于两个树模型或两个线性模型。
这意味着所有模型对预测的贡献是一样的。如果一些模型在某些情况下很好,而在其他情况下很差,这是使用投票法时需要考虑到的一个问题。
基于sklearn,介绍pipe管道的使用以及voting的使用
Sklearn中提供了回归投票器(VotingRegressor)与分类投票器(VotingClassifier) 两个投票方法。
这两种模型的操作方式相同,并采用相同的参数。
使用模型需要提供一个模型列表,列表中每个模型采用元组Tuple的结构表示,第一个元素代表名称,第二个元素代表模型,需要保证每个模型必须拥有唯一的名称。
例如:定义两个模型
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import VotingClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
estimators参数,
models = [('lr',LogisticRegression()),('svm',SVC())]
ensemble = VotingClassifier(estimators=models)
可以通过pipeline简化预处理模型过程
models = [('lr',LogisticRegression()),
('svm',make_pipeline(StandardScaler(),SVC()))]
ensemble = VotingClassifier(estimators=models)
voting参数,选择分类投票器类型
models = [('lr',LogisticRegression()),('svm',SVC())]
ensemble = VotingClassifier(estimators=models, voting='soft')
实际案例
创建一个1000个样本,20个特征的随机数据集:
# test classification dataset
from sklearn.datasets import make_classification
# define dataset
def get_dataset():
X, y = make_classification( n_samples=1000,
n_features=20,
n_informative=15,
n_redundant=5,
random_state=2)
# summarize the dataset
return X,y
使用多个KNN模型作为基模型演示投票法,其中每个模型采用不同的邻居值K参数:
from sklearn.neighbors import KNeighborsClassifier
from matplotlib import pyplot
# 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
创建一个模型字典来评估投票带来的提升,包括KNN模型配置的每个独立版本和硬投票模型
# 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
#Added by ljq
from sklearn.model_selection import cross_val_score
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
我们得到的结果如下:
knn1 0.873 (0.030)
knn3 0.889 (0.038)
knn5 0.895 (0.031)
knn7 0.899 (0.035)
knn9 0.900 (0.033)
hard_voting 0.902 (0.034)
显然投票的效果略大于任何一个基模型。通过箱形图我们可以看到硬投票方法对交叉验证整体预测结果分布带来的提升。
拓展练习
用投票法对鸢尾花数据进行分类
# -*- coding: utf-8 -*-
"""
Created on Wed Apr 14 21:52:32 2021
@author: PC
"""
# 导入工具包
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
# 导入数据集
from sklearn import datasets
# 导入管道
from sklearn.pipeline import make_pipeline
# 数据预处理:归一化
from sklearn.preprocessing import StandardScaler
# logistic回归
from sklearn.linear_model import LogisticRegression
# 分类向量机
from sklearn.svm import SVC
# 分类决策树
from sklearn.tree import DecisionTreeClassifier
# 导入投票器
from sklearn.ensemble import VotingClassifier
# 评分
from sklearn.model_selection import cross_val_score
#直接k折检验,不用分割数据集了
from sklearn.model_selection import RepeatedStratifiedKFold
先对数据进行观察
def load_data():
# 下载数据并展示内容关键字
iris = datasets.load_iris()
print(iris.keys())
print(iris.data) # 展示所有数据
print(iris.feature_names) # 展示特征名
print(iris.target) # 展示目标结果
print(iris.target_names) # 展示目标结果含义
print(type(iris.data)) # 数据类型
print(type(iris.target)) # 目标结果类型
print(iris.data.shape) # 确认行列维度
print(iris.target.shape)
load_data()
共有150个样本,4个特征,1个目标值
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
[4.6 3.1 1.5 0.2]
…
[5.9 3. 5.1 1.8]]
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
[0 0 0 0 ……1 1 1 1 1 …… 2 2 2]
['setosa' 'versicolor' 'virginica']
<class 'numpy.ndarray'>
<class 'numpy.ndarray'>
(150, 4)
(150,)
models = [('lr',LogisticRegression()),
('svm',make_pipeline(StandardScaler(),SVC(probability=True))),
('tree', DecisionTreeClassifier(random_state=10))]
ensemble = VotingClassifier(estimators=models,voting='hard')
def get_models():
models = dict()
models['lr'] = LogisticRegression()
models['svm'] = make_pipeline(StandardScaler(),SVC(probability=True))
models['tree'] = DecisionTreeClassifier(random_state=10)
models['hard_voting'] = ensemble
return models
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
# 给X,Y进行赋值
iris = datasets.load_iris()
X = iris.data
y = iris.target
# get the models to evaluate
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)
结果
>lr 0.964 (0.041)
>svm 0.962 (0.048)
>tree 0.951 (0.057)
>hard_voting 0.964 (0.041)