最近在做多分类器的集成(ensemble),主要有bagging和boosting,这篇文章主要讲的是分类,采用的分类器属于强分类器,有随机森林(RandomForestClassifier)、xgb(xgboost)、决策树(DecisionTreeClassifier)、逻辑斯特回归(LogisticRegression)以及梯度下降boost(GradientBoostingClassifier),目的是实验强分类器的集成对结果的精度是否有所提高。
一、bagging
每个分类器的权重一样
- 从初始训练集取出n个训练样本(可放回取样)
- 每个训练集训练一个分类器,一共可以得到n个模型
- 将每个模型预测得出的结果进行voting(多数表决),即少数服从多数
二、boosting
是一种将弱分类器集成的方法,这里介绍adaboost算法,是boosting系列算法中的一种,跟bagging不同的是,它给不同的分类器赋予不同的权重,它的基分类器可以是同类分类器也可以是不同的分类器。
运行过程是:给每一个样本赋予权重D,初始的样本权重是相等的。训练后计算分类器的错误率,根据错误率ε对样本的权重进行调整(分类正确的样本权重会降低,分类错误的样本权重会上升),再进行二次、三次...训练,最终给不同的 分类器分配不同的权重alpha(分类器的错误率低则权重高)
这里要注意的是调整样本权重是为了训练模型,每次更新完权重就进行下一次的迭代训练
分类器权重:alpha=0.5*ln(1-ε/max(ε,1e-16))
更新样本权重: 如果某个样本被正确分类,那么权重更新为:
D(m+1,i)=D(m,i)*exp(-alpha)/sum(D)
如果某个样本被错误分类,那么权重更新为:
D(m+1,i)=D(m,i)*exp(alpha)/sum(D)
三、基于不同分类器的boosting算法
注意:
- 迭代过程样本权重更新用于训练模型
- 模型训练中,要更新权重之前要计算错误率,将用于训练的样本再进行计算错误率,结果是没什么意义的,所以这里训练过程分为训练集和测试集。
- 由D更新样本的公式,分类正确的样本和错误的样本给予不同的权重。由第2我们可以得知这里的权重更新是训练集的权重更新,当我们知道测试集的分类结果后我们得出测试集的样本更新是没有意义的。所以我们需要将训练集再次预测,得出该模型下训练集的分类情况,由此来更新训练集的样本权重。综上,训练集的预测是为了更新样本,而训练集的预测是为了获取错误率。
- 最后得出不同分类器的预测结果,以及分类器的权重,得出最后的结果,计算准确率
代码如下:
from sklearn.cross_validation import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.ensemble import RandomForestClassifier
from sklearn import cross_validation
import xgboost
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier
def split_data(feat, labels):
'''
划分训练集和测试集
'''
x_train, x_test, y_train, y_test = train_test_split(feat, labels)
return x_train, x_test, y_train, y_test
def init_classifier():
'''
分类器的初始化构造
'''
clf1 = RandomForestClassifier()
clf2 = xgboost.XGBClassifier()
clf3 = DecisionTreeClassifier()
clf4 = LogisticRegression()
clf5 = GradientBoostingClassifier()
return clf1, clf2, clf3, clf4, clf5
def boosting_clf(num, data1, labels1, clf, data2):
'''
分类器clf的adaboost算法
param:
num:训练迭代次数
data1:数据集
labels1:标签
data2:最终的测试集
return:
alpha:分类器的权重
pre:对最终测试集的测试结果
'''
#划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(data1, labels1, test_size=0.3)
#刚开始样本权重是均值
w = np.ones(len(x_train)) / len(x_train)
#定义最大准确率
max_acc = 0
#定义分类器最终的alpha
result_alpha = 0
#要保存那个结果最好的分类器了,只要保存他的即可
best_w = np.zeros(len(x_train))
#分类器训练
for i in range(num):
clf.fit(x_train, y_train, sample_weight=w)
#预测
#训练集的预测用于更新w
pre0 = clf.predict(x_train)
#测试集上的预测用于修改alpha
pre1 = clf.predict(x_test)
#将y_test转换为array类型
tt = y_train.values.reshape((1, len(y_train)))[0]
#相同的为0,不同的为1,计算训练集上的miss
miss = [int(t) for t in (pre0 != tt)]
#计算测试集上的准确率
acc = accuracy_score(pre1, y_test)
#计算alpha
alpha = 0.5*(np.log((acc)/(1-acc)))
#在训练集上更新权重
w = np.multiply(w,np.exp([-alpha * s for s in miss]))
if acc > max_acc:
max_acc = acc
result_alpha = alpha
best_w = w
#训练完毕
#重新将训练结果进行训练(因为不确定最优的那个结果一定是最后一次训练的分类器)
clf.fit(x_train, y_train, sample_weight=best_w)
pre = clf.predict(data2)
return result_alpha, pre
def train(feat):
'''
输入特征集进行训练
返回准确率
'''
data1, data2, labels1, labels2 = split_data(feat, labels)
clf1, clf2, clf3, clf4, clf5 = init_classifier()
#训练2个分类器
a1, p1= boosting_clf(400, data1, labels1, clf1, data2)
a2, p2= boosting_clf(400, data1, labels1, clf2, data2)
#归一化不同分类器的权重
alp1 = a1 / (a1+a2)
alp2 = a2 / (a1+a2)
#计算最终的预测值
pre = alp1*p1 + alp2*p2
#将预测值四舍五入
pre = np.round(pre)
#计算准确率
acc = accuracy_score(pre, labels2)
return acc
if __name__ == "main":
acc = train(color)
print(acc)
通过train()里面调用的boosting_clf可以更改分类器,同时要修改alpha的计算,color为图片的color特征,传入color的特征集后,得到的准确率:
迭代次数为200:准确率为0.7070484581497798
迭代次数为300:准确率为0.7158590308370044
迭代次数为400:准确率为0.7312775330396476
迭代次数为500:准确率为0.6872246696035242