1. 定义
投票法是一种遵循少数服从多数原则的集成学习模型,通过多个模型的集成降低方差,从而提高模型的
鲁棒性。在理想情况下,投票法的预测效果应当优于任何一个基模型的预测效果。
投票法在回归模型与分类模型上均可使用:
- 回归投票法:预测结果是所有模型预测结果的平均值。
- 分类投票法:预测结果是所有模型种出现最多的预测结果。
2. 分类
对分类任务来说, 学习器 h i h_{i} hi 将从类别标记集合 $ \left{c_{1}, c_{2}, \ldots, c_{N}\right} $ 中预测出一 个标记, 最常见的结合策略是使用投票法(voting). 为便于讨论, 我们将 h i h_{i} hi 在样 本 x x x 上的预测输出表示为一个 N N N 维向量 ( h i 1 ( x ) ; h i 2 ( x ) ; … ; h i N ( x ) ) \left(h_{i}^{1}(x) ; h_{i}^{2}(x) ; \ldots ; h_{i}^{N}(x)\right) (hi1(x);hi2(x);…;hiN(x)), 其中 h i j ( x ) h_{i}^{j}(x) hij(x) 是 h i h_{i} hi 在类别标记 c j c_{j} cj 上的输出.
-
绝对多数投票法(majority voting)
H ( x ) = { c j , if ∑ i = 1 T h i j ( x ) > 0.5 ∑ k = 1 N ∑ i = 1 T h i k ( x ) ; reject, otherwise. H(x)=\left\{\begin{array}{ll} c_{j}, & \text { if } \sum_{i=1}^{T} h_{i}^{j}(x)>0.5 \sum_{k=1}^{N} \sum_{i=1}^{T} h_{i}^{k}(x) ; \\ \text { reject, } & \text { otherwise. } \end{array}\right. H(x)={cj, reject, if ∑i=1Thij(x)>0.5∑k=1N∑i=1Thik(x); otherwise.
即若某标记得票过半数, 则预测为该标记; 否则拒绝预测. -
相对多数投票法(plurality voting)
H
(
x
)
=
argmax
j
∑
i
=
1
T
h
i
j
(
x
)
H(\boldsymbol{x})=\underset{j}{\operatorname{argmax}} \sum_{i=1}^{T} h_{i}^{j}(\boldsymbol{x})
H(x)=jargmaxi=1∑Thij(x)
即预测为得票最多的标记, 若同时有多个标记获最高票, 则从中随机选取一个.
-
加权投票法(weighted voting)
H ( x ) = c argmax j ∑ i = 1 T w i h i j ( x ) H(\boldsymbol{x})=c_{\underset{j}{\operatorname{argmax}}} \sum_{i=1}^{T} w_ih_{i}^{j}(\boldsymbol{x}) H(x)=cjargmaxi=1∑Twihij(x)与加权平均法类似, w i w_{i} wi 是 h i h_{i} hi 的权重, 通常 w i ⩾ 0 , ∑ i = 1 T w i = 1 w_{i} \geqslant 0, \sum_{i=1}^{T} w_{i}=1 wi⩾0,∑i=1Twi=1
标准的绝对多数投票法提供了“拒绝预测”选项, 这在可靠性要求 较高的学习任务中是一个很好的机制. 但若学习任务要求必须提供预测结果, 则绝对多数投票法将退化为相对多数投票法. 因此, 在不允许拒绝预测的任务 中, 绝对多数、相对多数投票法统称为“多数投票法”.
上述式子没有限制个体学习器输出值的类型. 在现实任务中,不同 类型个体学习器可能产生不同类型的 h i j ( x ) h_{i}^{j}(\boldsymbol{x}) hij(x) 值, 常见的有:
-
类标记: h i j ( x ) ∈ { 0 , 1 } h_{i}^{j}(\boldsymbol{x}) \in\{0,1\} hij(x)∈{0,1}, 若 h i h_{i} hi 将样本 x \boldsymbol{x} x 预测为类别 c j c_{j} cj 则取值为 1, 否则为0,使用类标记的投票亦称“硬投票” (hard voting)。
-
类概率: h i j ( x ) ∈ [ 0 , 1 ] h_{i}^{j}(\boldsymbol{x}) \in[0,1] hij(x)∈[0,1], 相当于对后验概率 P ( c j ∣ x ) P\left(c_{j} \mid \boldsymbol{x}\right) P(cj∣x) 的一个估计. 使用类概率的投票亦称“软投票”(soft voting)。
-
分类又可分为硬投票和软投票。
硬投票(Hard Voting Classifier):根据少数服从多数来定最终结果;
软投票(Soft Voting Classifier):将所有模型预测样本为某一类别的概率的平均值作为标准,概 率最高的对应的类型为最终的预测结果;
Hard Voting: 模型 1中 A - 99%、B - 1%,表示模型 1 认为该样本是 A 类型的概率为 99%,为 B 类型 的概率为 1%;
Soft Voting 将所有模型预测样本为某一类别的概率的平均值作为标准;
从这个例子我们可以看出,软投票法与硬投票法可以得出完全不同的结论。相对于硬投票,软投票法考
虑到了预测概率这一额外的信息,因此可以得出比硬投票法更加准确的预测结果。
3. 使用
在投票法中,我们还需要考虑到不同的基模型可能产生的影响。理论上,基模型可以是任何已被训练好
的模型。但在实际应用上,想要投票法产生较好的结果,需要满足两个条件:
- 基模型之间的效果不能差别过大。当某个基模型相对于其他基模型效果过差时,该模型很可能成为
噪声。 - 基模型之间应该有较小的同质性。例如在基模型预测效果近似的情况下,基于树模型与线性模型的
投票,往往优于两个树模型或两个线性模型。
当投票合集中使用的模型能预测出清晰的类别标签时,适合使用硬投票。当投票集合中使用的模型能预
测类别的概率时,适合使用软投票。软投票同样可以用于那些本身并不预测类成员概率的模型,只要他
们可以输出类似于概率的预测分数值(例如支持向量机、k-最近邻和决策树)。
投票法的局限性在于,它对所有模型的处理是一样的,这意味着所有模型对预测的贡献是一样的。如果
一些模型在某些情况下很好,而在其他情况下很差,这是使用投票法时需要考虑到的一个问题。
4. 代码
from matplotlib import pyplot as plt
from numpy.core import mean, std
from sklearn.ensemble import VotingClassifier
from sklearn.model_selection import RepeatedStratifiedKFold, cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import make_classification
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
# 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
# 分层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
def get_dataset():
# 创建1000个样本,20个特征的数据
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=2)
return X,y
# summarize the dataset
# print(X.shape, y.shape)
# define dataset
if __name__ == '__main__':
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, mean(scores), std(scores)))
# plot model performance for comparison
plt.figure(figsize=(10, 4))
plt.boxplot(results, labels=names, showmeans=True)
plt.sav
plt.show()
"""
输出结果:
>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)
通过不同模型的得分比较,显然投票的效果略大于任何一个基模型。
"""
通过箱形图我们可以看到硬投票方法对交叉验证整体预测结果分布带来的提升。