投票分类

假设你已经训练了一些分类器,每一个都有 80% 的准确率。你可能有了一个逻辑斯蒂回归、或一个 SVM、或一个随机森林,或者一个 KNN,或许还有更多(详见图 7-1)

图7-1

一个非常简单去创建一个更好的分类器的方法就是去整合每一个分类器的预测然后经过投票去预测分类。这种分类器就叫做硬投票分类器(详见图 7-2)。

图7-2

令人惊奇的是这种投票分类器得出的结果经常会比集成中最好的一个分类器结果更好。事实上,即使每一个分类器都是一个弱学习器(意味着它们也就比瞎猜好点),集成后仍然是一个强学习器(高准确率),只要有足够数量的弱学习者,他们就足够多样化。

这怎么可能?接下来的分析将帮助你解决这个疑问。假设你有一个有偏差的硬币,他有 51% 的几率为正面,49% 的几率为背面。如果你实验 1000 次,你会得到差不多 510 次正面,490 次背面,因此大多数都是正面。如果你用数学计算,你会发现在实验 1000 次后,正面概率为 51% 的人比例为 75%。你实验的次数越多,正面的比例越大(例如你试验了 10000 次,总体比例可能性就会达到 97%)。这是因为大数定律 :当你一直用硬币实验时,正面的比例会越来越接近 51%。图 7-3 展示了始终有偏差的硬币实验。你可以看到当实验次数上升时,正面的概率接近于 51%。最终所有 10 种实验都会收敛到 51%,它们都大于 50%。

图7-3

同样的,假设你创建了一个包含 1000 个分类器的集成模型,其中每个分类器的正确率只有 51%(仅比瞎猜好一点点)。如果你用投票去预测类别,你可能得到 75% 的准确率!然而,这仅仅在所有的分类器都独立运行的很好、不会发生有相关性的错误的情况下才会这样,然而每一个分类器都在同一个数据集上训练,导致其很可能会发生这样的错误。他们可能会犯同一种错误,所以也会有很多票投给了错误类别导致集成的准确率下降。

如果使每一个分类器都独立自主的分类,那么集成模型会工作的很好。去得到多样的分类器的方法之一就是用完全不同的算法,这会使它们会做出不同种类的错误,这会提高集成的正确率

接下来的代码创建和训练了在 sklearn 中的投票分类器。这个分类器由三个不同的分类器组成(训练集是第五章中的 moons 数据集):

  1. >>> from sklearn.ensemble import RandomForestClassifier
  2. >>> from sklearn.ensemble import VotingClassifier
  3. >>> from sklearn.linear_model import LogisticRegression
  4. >>> from sklearn.svm import SVC
  5. >>> log_clf = LogisticRegression()
  6. >>> rnd_clf = RandomForestClassifier()
  7. >>> svm_clf = SVC()
  8. >>> voting_clf = VotingClassifier(estimators=[('lr', log_clf), ('rf', rnd_clf), >>> ('svc', svm_clf)],voting='hard')
  9. >>> voting_clf.fit(X_train, y_train)

让我们看一下在测试集上的准确率:

  1. >>> from sklearn.metrics import accuracy_score
  2. >>> for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
  3. >>> clf.fit(X_train, y_train)
  4. >>> y_pred = clf.predict(X_test)
  5. >>> print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
  6. LogisticRegression 0.864
  7. RandomForestClassifier 0.872
  8. SVC 0.888
  9. VotingClassifier 0.896

你看!投票分类器比其他单独的分类器表现的都要好。

如果所有的分类器都能够预测类别的概率(例如他们有一个predict_proba()方法),那么你就可以让 sklearn 以最高的类概率来预测这个类,平均在所有的分类器上。这种方式叫做软投票。他经常比硬投票表现的更好,因为它给予高自信的投票更大的权重。你可以通过把voting="hard"设置为voting="soft"来保证分类器可以预测类别概率。然而这不是 SVC 类的分类器默认的选项,所以你需要把它的probability hyperparameter设置为True(这会使 SVC 使用交叉验证去预测类别概率,其降低了训练速度,但会添加predict_proba()方法)。如果你修改了之前的代码去使用软投票,你会发现投票分类器正确率高达 91%