集成算法
集成算法(融合算法)
元算法(meta-algorithm)
思路:对其他算法进行组合。
使用集成算法时有多种形式:
不同算法的集成;
同一算法在不同设置下的集成;
数据集不同部分,分配给不同分类器之后的集成。
bagging(bootstrap aggregating) 自举汇聚法
定义:从原始数据集选择S次后得到S个新数据集的一种技术, 新数据集和原数据集大小相等。每个数据集都是从原始数据集中
随机选择一个得到的,允许新数据中有重复的值
思想:
使用不同数据集分别训练模型,然后将多个不同模型预测结果融合产生预测值。
数据产生方式:有放回重采样,产生不同数据【样本数目不一样,数据样本不一样】
作用:
不同数据集训练,模型考虑样本特征不同,部分模型对特殊特征值进行学习,在多个模型融合时,特殊特征信息将会过滤掉,
使模型更有鲁棒性,缓解模型过拟合。
经典算法: 随机森林
构件过程:
1、从原始数据中重采样m条数据,去重得到子数据;
2、利用子数据构件决策树模型,选择划分特征时,引入随机特征划分:
a. 从原始特征中随机选择k个特征,从k个特征中选择最优划分的特征作为当前节点划分(此时为最优局部划分,可以降低模型过拟合);
3、使用上述步骤构件N次,产生N个模型,形成随机森林模型;
4、使用N个模型对样本进行预测,对N个结果进行融合(分类:多数投票; 回归:均值)
boosting
思想:
使用一种模型迭代,使每一步模型构建都是让模型的最终预测更加精准;
让模型误差率越来越小,即模型构建需要基于之前模型预测结果之上。
作用:主要作用提高模型欠拟合
区别:
boosting集中关注被已有分类器错分的那些数据来获得新的分类器
boosting分类结果是,基于所有分类器的加权求和结果的,bagging中权重相等,boosting中权重不等;
每个权重代表对应分类器在上一轮中成功度。
经典算法:AdaBoost, GBDT, XGBoost
注:boosting有多个版本,流行版本为AdaBoost
AdaBoost(adaptive boosting)自适应boost
优点:泛化错误率低, 容易编码,可以应用在大部分分类器上,无参数调整;
缺点:对离群点敏感;
思想:
通过修改样本权重系数,改变模型构建时,各个样本预测失败带来损失函数值,让模型构建时,对于权重系数较大样本着重考虑,
尽可能让权重过大的样本预测成功。
模型融合时,对预测精准的基模型,给一个较大权重,相当预测精准模型可信度相对较大
构建过程:
1、给定所有样本初始权重一致
2、基于样本及样本权重训练一个基模型,在基模型构建过程中,对于样本权重大的样本,预测比较准确
3、训练好基模型后,计算出当前基模型在训练集上准确率,准确率越高预测结果越可信
4、如果预测失败,增加样本权重,让样本在下一个模型构建时,具有更大的影响因子,预测成功,减小权重
5、当错误率或子模型数目达到一定限制时,结束模型训练
代码实例:
单层决策树构建
boost.py
from numpy import *
def loadSimpData():
datMat = matrix(
[[1., 2.1],
[2., 1.1],
[1.3, 1.],
[1., 1.],
[2., 1.]]
)
classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
return datMat, classLabels
def stumpClassify(dataMatrix, dimen, threshVal, threshIneq):
"""
通过阈值比较,对数据分类
:param dataMatrix:
:param dimen:
:param threshVal:
:param threshIneq:
:return:
"""
retArray = ones((shape(dataMatrix)[0], 1))
if threshIneq == 'lt':
retArray[dataMatrix[:, dimen] <= threshVal] = -1.0
else:
retArray[dataMatrix[:, dimen] > threshVal] = -1.0
return retArray
def buildStump(dataArr, classLabels, D):
"""
构建单层决策树
:param dataArr:
:param classLabels:
:param D:
:return:
"""
dataMatrix = mat(dataArr)
labelMat = mat(classLabels).T
m, n = shape(dataMatrix)
numSteps = 10.0
bestStump = {} # 存储给定权重向量D时,所得到的最佳单层决策树的相关信息
bestClasEst = mat(zeros((m, 1)))
minError = inf
for i in range(n):
rangeMin = dataMatrix[:, i].min()
rangeMax = dataMatrix[:, i].max()
stepSize = (rangeMax - rangeMin) / numSteps
for j in range(-1, int(numSteps)+1):
for inequal in ['lt', 'gt']:
threshVal = (rangeMin + float(j) * stepSize)
predictedVals = stumpClassify(dataMatrix, i, threshVal, inequal)
errArr = mat(ones((m, 1)))
errArr[predictedVals == labelMat] = 0
weightedError = D.T * errArr # 计算加权错误率
print(f'split: dim {i}, '
f'thresh {threshVal}, '
f'thresh inequal: {inequal}, '
f'the weighted error is {weightedError}')
if weightedError < minError:
minError = weightedError
bestClasEst = predictedVals.copy()
bestStump['dim'] = i
bestStump['thresh'] = threshVal
bestStump['ineq'] = inequal
return bestStump, minError, bestClasEst
if __name__ == '__main__':
datMat, classLabels = loadSimpData()
D = mat(ones((5, 1)) / 5)
buildStump(datMat, classLabels, D)
adaboost
弱分类器为单层决策树
from numpy import *
from test.machine_learning.algorithm.ada_boost.boost import buildStump, stumpClassify
def loadSimpData():
datMat = matrix(
[[1., 2.1],
[2., 1.1],
[1.3, 1.],
[1., 1.],
[2., 1.]]
)
classLabels = [1.0, 1.0, -1.0, -1.0, 1.0]
return datMat, classLabels
def adaBoostTrainDs(dataArr, classLabels, numIt=40):
"""
单层决策树adaBoost训练过程
:param dataArr:
:param classLabels:
:param numIt: 分类器的数目
:return:
"""
weakClassArr = []
m = shape(dataArr)[0]
D = mat(ones((m, 1)) / m)
aggClassEst = mat(zeros((m, 1)))
for i in range(numIt):
bestStump, error, classEst = buildStump(dataArr, classLabels, D)
print(f'D: {D.T}')
alpha = float(0.5 * log((1.0-error) / max(error, 1e-16))) # max(error, 1e-16) 确保错误时,不会发生零的溢出
bestStump['alpha'] = alpha
weakClassArr.append(bestStump)
print(f'classEst: {classEst.T}')
expon = multiply(-1 * alpha * mat(classLabels).T, classEst)
D = multiply(D, exp(expon))
D = D / D.sum()
aggClassEst += alpha * classEst
print(f'aggClassEst: {aggClassEst.T}')
aggErrors = multiply(sign(aggClassEst) != mat(classLabels).T, ones((m, 1)))
errorRate = aggErrors.sum()/m
print(f'total error: {errorRate}')
if errorRate == 0:
break
return weakClassArr, aggClassEst
def adaClassify(datToClass, classifierArr):
dataMatrix = mat(datToClass)
m = shape(dataMatrix)[0]
aggClassEst = mat(zeros((m, 1)))
for i in range(len(classifierArr)):
classEst = stumpClassify(dataMatrix, classifierArr[i]['dim'],
classifierArr[i]['thresh'],
classifierArr[i]['ineq'])
aggClassEst += classifierArr[i]['alpha'] * classEst
print(f'aggClassEst: {aggClassEst}')
return sign(aggClassEst)
def loadDataSet(fileName):
"""
自适应数据加载函数
:param fileName:
:return:
"""
fr = open(fileName)
numFeat = len(fr.readline().split('\t'))
dataMat = []
labelMat = []
for line in fr.readlines():
lineArr = []
curLine = line.strip().split('\t')
for i in range(numFeat-1):
try:
lineArr.append(float(curLine[i]))
except Exception:
pass
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
# currLine = line.strip().split()
# lineArr = []
# for i in range(21):
# lineArr.append(float(currLine[i]))
# dataMat.append(lineArr)
# labelMat.append(float(currLine[21]))
return dataMat, labelMat
def plotROC(predStrengths, classLabels):
"""
ROC曲线绘制
:param predStrengths:
:param classLabels:
:return:
"""
import matplotlib.pyplot as plt
cur = (1.0, 1.0)
ySum = 0
numPosClas = sum(array(classLabels) == 1.0)
yStep = 1/float(numPosClas)
xStep = 1/float(len(classLabels)-numPosClas)
sortedIndicies = predStrengths.argsort()
fig = plt.figure()
fig.clf()
ax = plt.subplot(111)
for index in sortedIndicies.tolist()[0]:
if classLabels[index] == 1.0:
delX = 0
delY = yStep
else:
delX = xStep
delY = 0
ySum += cur[1]
ax.plot([cur[0], cur[o]-delX], [cur[1], cur[1]-delY], c='b')
cur = (cur[0]-delX, cur[1]-delY)
ax.plot([0, 1], [0, 1], 'b--')
plt.xlabel('False Positive Rate')
plt.ylabel('True positive Rate')
plt.title('ROC curve for AdaBoost Horse Colic Detection System')
ax.axis([0, 1, 0, 1])
plt.show()
print(f'the Area Under the Curve is {ySum*xStep}')
if __name__ == '__main__':
# datMat, classLabels = loadSimpData()
# classifierArray = adaBoostTrainDs(datMat, classLabels, 9)
# cla = adaClassify([[5, 5],[0, 0]], classifierArray)
# print(cla)
# 在难数据集上的应用
datArr, labelArr = loadDataSet(r"D:\workplace\data\tensorflow\logistic_data\horse-colic.data")
classifierArray, aggClassEst = adaBoostTrainDs(datArr, labelArr, 10)
plotROC(aggClassEst.T, labelArr)
GBDT
思想:
通过修改标签y值,让每次构建的模型误差足够小,当模型误差值最小时,所对应的标签值就是最优值
采用损失函数梯度值作为下一个模型构建时新y值标签
构建过程:
1、 训练基础模型;
2、基于当前模型计算损失函数梯度值,更新训练中标签值,使用梯度值作为标签值;
3、基于标签值更新的数据训练下一个模型;
4、当损失函数值或子模型数目达到一定限制时,结束模型训练。
预测过程:所有子模型累加值就是最终预测值
XGBoost和GBDT区别:
1、加入模型复杂度考虑, 防止模型存在过拟合;
2、底层构建时,GBDT是穿行构建, XGBoost 选择划分特征时,是并行构建
3、GBDT底层只是支持决策树,XGBoost支持决策树,线性回归等模型