集成方法的思想其实很好理解,简单来说就是构建很多个分类器,然后每个分类器分别预测,聚合每个分类器的预测结果,然后投票,将得票最多的结果作为预测类别。
下面我们通过程序来实现一个投票分类器。首先构建多个分类器,然后把这些分类器合并在一起,组合成一个投票分类器。
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import load_iris
iris = load_iris()
X_train = iris.data[:140, 2:] # 长和宽
y_train = iris.target[:140]
X_test = iris.data[140:-1, 2:]
y_test = iris.target[140:-1]
log_clf = LogisticRegression() # 逻辑回归分类器
svm_clf = SVC()
# 支持向量机分类器
tree_clf = DecisionTreeClassifier() # 决策树分类器
voting_clf = VotingClassifier(estimators=[('lr',log_clf),('svm',svm_clf),('tree',tree_clf)], voting='hard') # 合并为一个分类器
voting_clf.fit(X_train,y_train)
from sklearn.metrics import accuracy_score
for clf in (log_clf, svm_clf, tree_clf, voting_clf):
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
# 输出:
LogisticRegression 1.0
SVC 1.0
DecisionTreeClassifier 1.0
VotingClassifier 1.0
可能是因为鸢尾花数据集数据量比较小,所以输出的结果得分都是1.0。我们换成手写数字识别数据集再来看看。
from sklearn import datasets
digits = datasets.load_digits()
x = digits['data']
y = digits['target']
X_train = x[:1600]
y_train = y[:1600]
X_test = x[1600:]
y_test = y[1600:]
for clf in (log_clf, svm_clf, tree_clf, voting_clf):
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
# 输出:
LogisticRegression 0.9289340101522843
SVC 0.9390862944162437
DecisionTreeClassifier 0.7868020304568528
VotingClassifier 0.934010152284264
可以看到,现在输出就有差别了,不过由于支持向量机的性能确实突出,多个分类器投票后,居然还拉低了一点投票分类器的分数。不过也确实说明了投票分类器的结果是几个分类器投票集成的结果。
from sklearn.datasets import make_moons
X,y = make_moons(n_samples=10000, noise=0.15)
X_train = X[:9000]
y_train = y[:9000]
X_test = X[9000:]
y_test = y[9000:]
for clf in (log_clf, svm_clf, tree_clf, voting_clf):
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(clf.__class__.__name__, accuracy_score(y_test, y_pred))
# 输出:
LogisticRegression 0.87
SVC 0.992
DecisionTreeClassifier 0.991
VotingClassifier 0.992
可以看到,在卫星数据集上,投票分类器和SVM分类器的结果是非常接近的,因为几个分类器的结果都有了提升,因此集成在一起的精度也有提升。
bagging和pasting
bagging和pasting是两种不同的集成算法策略。如果使用同一种分类器训练,但是在不同的训练数据集上进行训练,这个训练数据集是原始训练数据集的子集,也就是一种抽样。如果是有放回的抽样,那么就是bagging算法,如果采样时样本不放回,那就是pasting算法。
代码如下:
bagging
from sklearn.ensemble import BaggingClassifier
bagging_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500, bootstrap=True, n_jobs=-1, oob_score=True)
bagging_clf.fit(X_train, y_train)
y_pred = bagging_clf.predict(X_test)
accuracy_score(y_test, y_pred)
#输出:0.993
pasting
from sklearn.ensemble import BaggingClassifier
bagging_clf = BaggingClassifier(DecisionTreeClassifier(), n_estimators=500, bootstrap=False, n_jobs=-1)
bagging_clf.fit(X_train, y_train)
y_pred = bagging_clf.predict(X_test)
accuracy_score(y_test, y_pred)
#输出:0.991
可以看到bagging和pasting的预测得分很接近,不过还是bagging的效果略好与pasting。
随机森林
随机森林算法就是决策树的集成算法,可以用bagging方法也可以用pasting方法。借助sklearn,我们可以很方便的是使用随机森林。
from sklearn.ensemble import RandomForestClassifier
rnd_clf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rnd_clf.fit(X_train, y_train)
y_pred = rnd_clf.predict(X_test)
accuracy_score(y_test, y_pred)
#输出:0.99
可以看到,预测的打分也达到了0.99。
AdaBoosting和梯度提升
AdaBoosting是一组有前后顺序的分类器,把前一个分类器结果中错分的样本,提升其权重,输入到第二个分类器,继续更新权重,以此类推,使得模型越来越好;梯度提升和AdaBoosting的区别在于,梯度提升法的分类器是拟合前一个分类器的预测结果和真实结果的误差,通过不断地拟合这个误差来提升模型的训练精度,使得模型越来越好。
AdaBoosting
from sklearn.ensemble import AdaBoostClassifier
ada_clf = AdaBoostClassifier(DecisionTreeClassifier(), n_estimators=500, algorithm="SAMME.R", learning_rate=0.5)
ada_clf.fit(X_train, y_train)
y_pred = ada_clf.predict(X_test)
accuracy_score(y_test, y_pred)
#输出:0.99
打印出决策边界看看:
from sklearn.datasets import make_moons
import numpy as np
import matplotlib.pyplot as plt
ada_clf = AdaBoostClassifier(DecisionTreeClassifier(), n_estimators=500, algorithm="SAMME.R", learning_rate=0.5)
ada_clf.fit(X, y)
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 # 生成两个坐标轴的范围,生成密集可以看得更清楚
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
h=0.01
print(np.arange(y_min,y_max,h).shape)
xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
print(xx.shape)
print(yy.shape)
z=ada_clf.predict(np.c_[xx.ravel(),yy.ravel()]) # ravel表示把数组拉成一维数组,np.c_表示把按列拼接两个矩阵
z=z.reshape(xx.shape) # 转换成跟xx一样的维度
plt.contourf(xx, yy, z, cmap=plt.cm.Paired, alpha=0.8) # 按z来画出决策边界
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired) # 按y来画出原始数据的散点图
plt.show()
可以看到边界比较清晰的划分出来了。
梯度提升
from sklearn.ensemble import GradientBoostingClassifier
gb_clf = GradientBoostingClassifier(learning_rate=0.5, n_estimators=100)
gb_clf.fit(X_train, y_train)
y_pred = gb_clf.predict(X_test)
accuracy_score(y_test, y_pred)
#输出:0.992
同样的,我们也输出决策边界:
from sklearn.datasets import make_moons
import numpy as np
import matplotlib.pyplot as plt
gb_clf = GradientBoostingClassifier(learning_rate=0.5, n_estimators=100)
gb_clf.fit(X, y)
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 # 生成两个坐标轴的范围,生成密集可以看得更清楚
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
h=0.01
print(np.arange(y_min,y_max,h).shape)
xx,yy=np.meshgrid(np.arange(x_min,x_max,h),np.arange(y_min,y_max,h))
print(xx.shape)
print(yy.shape)
z=gb_clf.predict(np.c_[xx.ravel(),yy.ravel()]) # ravel表示把数组拉成一维数组,np.c_表示把按列拼接两个矩阵
z=z.reshape(xx.shape) # 转换成跟xx一样的维度
plt.contourf(xx, yy, z, cmap=plt.cm.Paired, alpha=0.8) # 按z来画出决策边界
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired) # 按y来画出原始数据的散点图
plt.show()
和Adaboosting算法的结果非常接近,虽然有少个几个样本分类错误,但总体上非常准确的划分了数据集。
网友评论