集成学习之投票法与bagging
投票法简介
痛点:
算法得出的单一结果可能存在偏差,因此融合多个数据是降低误差的一个好方法,这就是投票法的基本思路。
分类(投票可以用于分类和回归模型中):
按模型类型可分为:
- 回归投票法:输出为所有结果的加权(平均)值;
- 分类投票法:输出出现最多的结果;
分类模型的投票可分为:
- 硬投票:结果为投票出现最多的类;
- 软投票:结果为每个模型概率加和最大的类;
硬投票和软投票举例:
硬投票:
模型1的预测结果:类别A
模型2的预测结果:类别B
模型3的预测结果:类别B
- 最后统计输出最多的是B
软投票:
模型1 预测类别A的概率为 99%
模型2 预测类别A的概率为 49%
模型3 预测类别A的概率为 49%
- 最后统计类别A的预测结果平均是(99+49+49)/3=65.67%,软投票的结果根据加权平均计算;
投票法中注意点:
考虑不同基模型可能产生的影响,需要具备两个条件:
- 基模型之间的效果不能太大,否则很可能成为噪声;
- 基模型之间应有较小的同质性,例如在结果相似的情况下,线性模型和树模型的组合往往比两个树模型效果好。
投票合集能得到清晰的类别标签,适合用硬投票。
投票集合中使用的模型能预测类别的概率,适合用软投票。
投票法基础案例分析(基于sklean pipe管道的使用以及voting的使用)
- 由教程中得到
模型需要的预处理操作,可以为他们定义Pipeline完成模型预处理。
模型提供了voting参数让我们选择软投票或硬投票。
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
models = [('lr', LogisticRegression()),
('svm', make_pipeline(StandardScaler(), SVC()))
]
ensemble = VotingClassifier(estimators=models, voting='soft')
硬投票法(学习教程baseline)
训练基模型为KNN 并进行评估
# 构建样本并训练模型分类器
import numpy as np
from sklearn.datasets import make_classification
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
# 得到训练数据
def get_dataset():
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15,
n_redundant=5, random_state=2)
return X,y
# 训练模型投票
def get_voting():
# 定义基础模型
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)))
# 定义投票集成
ensemble = VotingClassifier(estimators=models, voting='hard')
return ensemble
# 创建模型列表评估单个模型
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
# 十倍交叉验证 三次重复的分数列表返回
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
# 训练模型 评估性能
from sklearn.neighbors import KNeighborsClassifier
from matplotlib import pyplot
# define dataset
X, y = get_dataset()
# 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
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
models = get_voting()
clf = models.fit(X, y)
y_pred = clf.predict(X)
micro = metrics.precision_score(y, y_pred, average='micro') # 微平均,精确率
print("模型精确率为:", micro)
模型精确率为: 0.95
软投票法案例
- 根据给出的baseline做出修改 采用软投票法
import numpy as np
from sklearn.naive_bayes import GaussianNB
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from sklearn.datasets import make_classification
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
def get_dataset():
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15,
n_redundant=5, random_state=2)
return X, y
def get_voting():
# 定义基础模型
models = list()
models.append(('lr' , LogisticRegression(multi_class='multinomial', random_state=5)))
models.append(('knn', KNeighborsClassifier(n_neighbors=7)))
models.append(('rf' , RandomForestClassifier(n_estimators=50, random_state=1)))
models.append(('gnb', GaussianNB()))
# 定义投票
ensemble = VotingClassifier(estimators=models, voting='soft')
return ensemble
# 创建模型列表评估单个模型
def get_models():
models = dict()
models['lr'] = LogisticRegression(multi_class='multinomial', random_state=5)
models['knn'] = KNeighborsClassifier(n_neighbors=7)
models['rf'] = RandomForestClassifier(n_estimators=50, random_state=1)
models['gnb'] = GaussianNB()
models['soft_voting'] = get_voting()
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
# 训练模型 评估性能
from sklearn.neighbors import KNeighborsClassifier
from matplotlib import pyplot
# define dataset
X, y = get_dataset()
# 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
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
from sklearn import metrics
models = get_voting()
clf = models.fit(X, y)
y_pred = clf.predict(X)
micro = metrics.precision_score(y, y_pred, average='micro') # 微平均,精确率
print("模型精确率为:", micro)
模型精确率为: 0.939
02 Bagging简介
问题痛点:
- 训练中模型差异不大,需要通过不同的采样方式增加模型的差异性;
解决方法:
- 核心是自主采样bootstrap,有放回的采样。
(Eg. 估计全国所有人年龄的平均值,在全国所有人口中随机抽取可能包含交集的集合),计算每个集合平均值,然后将所有平均值的均值作为估计值。
Bagging简介
Bagging的核心是自主采样(bootstrap),即有放回的从数据集中进行采样。同样一个样本可能被多次进行采样,如果希望得到全国所有人口年龄的平均值,我们可以在全国所有人口随机抽取不同集合,再计算几何平均值。
随机取一组样本放入采样集合,再把样本放回初始数据集,重复K次采样,最终可以获得大小为K的样本集合。同样方法,我们可以采样出T个含K个样本的集合,对每个样本集合训练一个基学习器,再将这些基学习器融合。
- 回归问题的预测是通过预测取平均值进行的;
- 分类问题的预测是通过预测取多数票预测进行的;
bagging可以降低方差,在不剪枝决策树和神经网络等易受样本扰动的学习器效果明显。实际使用中,加入列采样的Bagging对高维小样本有神奇的效果。
Bagging的案例分析(基于Sklearn 随机森林)
决策树的每个非叶子节点表示样本在一个特征上的判断,节点下方的分支表示对样本的划分。决策树的分支节点所包含的样本“纯度”尽可能高,节点划分过程中所用的指标主要是信息增益和GINI系数。
信息增益衡量的是划分前后信息不确定性成都的减小,信息不确定度通过信息熵度量,计算方式为:
H
(
Y
)
=
−
∑
p
i
l
o
g
p
i
H(Y) = - \sum p_i logp_i
H(Y)=−∑pilogpi
i表示样本的标签,p表示该样本出现的概率。当我们对样本呢做出划分之后,计算样本的条件熵:
H
(
Y
∣
X
)
=
−
∑
x
∈
X
p
(
X
=
x
)
H
(
Y
∣
X
=
x
)
H(Y|X) = - \sum_{x \in X} p(X = x) H(Y|X=x)
H(Y∣X)=−∑x∈Xp(X=x)H(Y∣X=x)
其中x表示用于划分的特征取值,信息增益定义为信息熵与条件熵的差值:$ IG = H(Y) - H(Y|X) $
信息增益IG越大,说明使用该特征划分数据所获得的信息量变化越大,子节点的样本“纯度”越高。
同样,我们可以用Gini指数来衡量数据的不纯度,计算方法如下:
$ Gini = 1 - \sum p_i^2 $
做出划分后,计算划分后的基尼系数:$ Gini_x = \sum_{x \in X} p(X = x)[1-\sum p_i^2] $
一般来说,选择划分后的Gini最小。
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15,
n_redundant=5, random_state=5)
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import BaggingClassifier
from sklearn.svm import SVC
# 设置数据集
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15,
n_redundant=5, random_state=5)
# 定义模型
model = BaggingClassifier(base_estimator=SVC(), n_estimators=10, random_state=0, bootstrap_features=True)
# 分析模型
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1,
error_score='raise')
# 评价结果
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))