import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
xMat=np.matrix([[1. ,2.1], #数据集
[2. ,1.1],
[1.3,1. ],
[1. ,1. ],
[2. ,1. ]])
yMat=np.mat([[ 1.], #预设分类结果,用于模型预测结果的校对
[ 1.],
[-1.],
[-1.],
[ 1.]]
plt.rcParams['font.sans-serif']=['Simhei']
def showPlot(xMat,yMat):
x=np.array(xMat[:,0])
y=np.array(xMat[:,1])
lable=np.array(yMat)
plt.scatter(x,y,c=lable)
plt.title('决策树桩测试数据')
plt.show()
showPlot(xMat,yMat)
lable=np.array(yMat)
plt.scatter(x,y,c=lable)
#scatter()的c即为color,yMat的内容只为1和-1,所以c=lable表示两种不同的颜色
''' 决策树桩分类函数: xMat:数据矩阵 i:第i列,也就是第几个特征 Q:阈值 S:标志 re:分类结果 '''
def Classify0(xMat,i,Q,S):
re=np.ones((xMat.shape[0],1)) #初始化re为一堆1
if(S=='lt'): #lt:less than
re[xMat[:,i]<=Q]=-1 #如果是less且小于阈值,则赋值为-1
elif(S=='gt'): #gt:greater than
re[xMat[:,i]>Q]=-1 #如果是greater且大于阈值,则赋值为-1
return re
对之后的def get_Stump(xMat,yMat,D)进行截断:
re=Classify0(xMat,i,Q,S)
print('Q:',Q,'\n','S:',S,'\n','re:\n',re,'\n')
对Q(阈值)的理解(举例):
数据集和预设分类结果:
决策树桩(基学习器):
其中的2.5就表示阈值Q啦,但并非所有的基学习器都是这个,因为阈值Q会发生移动:
(参考get_Stump(xMat,yMat,D)中的Q=(Min+j*stepSize))
截断示意图:
先初始化m和D后才能运行上方截断部分:
m=xMat.shape[0]
D=np.mat(np.ones((m,1))/m)
截断运行结果:
由此可知,对于每一个阈值Q,大于阈值和小于阈值的两个方向都遍历
(因为两个标签’lt’和’gt’都要遍历,参考def get_Stump(xMat,yMat,D)的for S in [‘lt’,‘gt’])
''' 找到数据集上最佳的决策树桩: xMat:特征矩阵 yMat:标签矩阵 D:样本权重 bestStump:最佳决策树桩信息 minE:最小误差 bestClas:最佳的分类结果 '''
def get_Stump(xMat,yMat,D):
m,n=xMat.shape #m为样本个数5,n为特征数2
Steps=10 #初始化步数
bestStump={} #用字典形式来储存树桩信息
bestClas=np.mat(np.zeros((m,1))) #初始化分类结果为1,5行1列
minE=np.inf #最小误差初始化为正无穷大
for i in range(n): #遍历所有特征
Min=xMat[:,i].min() #找到特征中最小值
Max=xMat[:,i].max() #找到特征中最大值
stepSize=(Max-Min)/Steps #计算总步长,用以移动阈值
for j in range(-1,int(Steps)+1):
for S in ['lt','gt']: #大于和小于的情况,两种方法均遍历;lt:less than, gt:greater than
Q=(Min+j*stepSize) #计算阈值
re=Classify0(xMat,i,Q,S) #决策树桩分类方法,得分类结果
err=np.mat(np.ones((m,1))) #初始化误差矩阵,一堆1
err[re==yMat]=0 #分类正确的,赋值为0,若分类错误,则为原数1
eca=D.T*err #计算误差
#print(f'切分特征:{i},阈值:{np.round(Q,2)},标志:{S},权重误差:{np.round(eca,3)}')
if(eca<minE): #找到误差最小的分类方式
minE=eca
bestClas=re.copy()
bestStump['特征列']=i
bestStump['阈值']=Q
bestStump['标志']=S
return bestStump,minE,bestClas
minE=np.inf
''' 这个函数的目的是通过寻找最小误差率得到对应的决策树桩,即为最佳的决策树桩, 因此不妨将误差率初始化为无穷大,在AdaBoost的迭代误差率会被更小的覆盖 (误差率会不断下降) '''
Steps=10
for i in range(n):
Min=xMat[:,i].min()
Max=xMat[:,i].max()
stepSize=(Max-Min)/Steps
'''stepSize为阈值Q的移动小步'''
''' 基于决策树桩的AdaBoost训练过程,训练出基学习器和最终训练结果 xMat:特征矩阵(数据集) yMat:标签矩阵(预设的分类结果,用于模型预测结果的校对) maxC:最大迭代次数 weakClass:基分类器 aggClass:最终类别估计值(即西瓜书P174的伪代码中H(x)中的累加量) '''
def Ada_train(xMat,yMat,maxC):
weakClass=[] #基学习器
m=xMat.shape[0]
D=np.mat(np.ones((m,1))/m) #初始化样本权重(每个样本权重相等)
aggClass=np.mat(np.zeros((m,1))) #最终结果的初始化
for i in range(maxC):
Stump,error,bestClas=get_Stump(xMat,yMat,D) #构建决策树桩
alpha=float(0.5*np.log((1-error)/max(error,1e-16))) #计算弱分类器权重alpha,即西瓜书P174伪代码的第6行
Stump['alpha']=np.round(alpha,2) #存储弱学习算法权重,保留两位小数
weakClass.append(Stump) #存储决策树桩
#以下3行为西瓜书的P174伪代码第7行的最终公式
expon=np.exp(np.multiply(-1*alpha*yMat,bestClas)) #计算e的指数项
D=np.multiply(D,expon)
D=D/D.sum() #根据样本权重公式,更新样本权重
#以下2行为西瓜书的P174伪代码的输出公式
aggClass+=alpha*bestClas #更新累计类别估计值
Hx=np.sign(aggClass) #最终分类结果
aggErr=np.multiply(Hx!=yMat,np.ones((m,1))) #计算误差
errRate=aggErr.sum()/m
print('分类错误率:',errRate)
if(errRate==0): break #当误差为0时,达到最优,退出循环
return weakClass,aggClass
weakClass,aggClass=Ada_train(xMat,yMat,40)
print('最佳基学习器:\n',weakClass,'\nH(x)中的累加量:\n',aggClass)
运行结果:
分类错误率: 0.2
分类错误率: 0.2
分类错误率: 0.0
最佳基学习器:
[{'特征列': 0, '阈值': 1.3, '标志': 'lt', 'alpha': 0.69},
{'特征列': 1, '阈值': 1.0, '标志': 'lt', 'alpha': 0.97},
{'特征列': 0, '阈值': 0.9, '标志': 'lt', 'alpha': 0.9 }]
H(x)中的累加量:
[[ 1.17568763]
[ 2.56198199]
[-0.77022252]
[-0.77022252]
[ 0.61607184]]
有好心人能在评论区帮我详细讲解一下下面这段代码怎么理解吗:)
aggErr=np.multiply(Hx!=yMat,np.ones((m,1))) #计算误差
errRate=aggErr.sum()/m
def AdaClassify(data,weakClass): #这里的weakClass为训练得到的最佳基学习器
dataMat=np.mat(data)
m=dataMat.shape[0]
aggClass=np.mat(np.zeros((m,1)))
#用上方训练出来的最佳基学习器进行测试:
for i in range(len(weakClass)): #遍历所有分类器,进行分类
classEst=Classify0(dataMat,
weakClass[i]['特征列'],
weakClass[i]['阈值'],
weakClass[i]['标志'])
aggClass+=weakClass[i]['alpha']*classEst
return np.sign(aggClass)
print(AdaClassify([0,0],weakClass)) #最终分类为-1
我不知道怎么把数据放上去…
def calAcc(maxC):
dataSetTrain=pd.read_table('E:/AdaBoost/horseColicTraining2.txt',header=None)
train_xMat=np.mat(dataSetTrain.iloc[:,:-1].values) #数据集
train_yMat=np.mat(dataSetTrain.iloc[:,-1].values).T #预设分类结果
weakClass,aggClass=Ada_train(train_xMat,train_yMat,maxC) #训练出最佳基学习器们
yhat=AdaClassify(train_xMat,weakClass)
#用训练出来的最佳基学习器们测试出H(x)即yHat(预测得的分类结果)
trainCorCount=0 #初始化准确个数为0
m=train_xMat.shape[0]
for i in range(m):
if(yhat[i]==train_yMat[i]):
trainCorCount+=1 #若某一预测结果正确累计+1
trainAcc=trainCorCount/m
print('训练集准确率为:',trainAcc)
testCorCount=0
dataSetTest=pd.read_table('E:/AdaBoost/horseColicTest2.txt',header=None)
test_xMat=np.mat(dataSetTest.iloc[:,:-1].values)
test_yMat=np.mat(dataSetTest.iloc[:,-1].values).T
yhat=AdaClassify(test_xMat,weakClass) #weakClass在上方已训练出来了
n=test_xMat.shape[0]
for i in range(n):
if(yhat[i]==test_yMat[i]):
testCorCount+=1
testAcc=testCorCount/n
print('测试集准确率为:',testAcc)
return trainAcc,testAcc
print(calAcc(40)) #迭代40次
运行结果:
分类错误率: 0.2842809364548495
分类错误率: 0.2842809364548495
分类错误率: 0.24749163879598662
分类错误率: 0.24749163879598662
分类错误率: 0.25418060200668896
分类错误率: 0.2408026755852843
分类错误率: 0.2408026755852843
分类错误率: 0.22073578595317725
分类错误率: 0.24749163879598662
分类错误率: 0.23076923076923078
分类错误率: 0.2408026755852843
分类错误率: 0.2140468227424749
分类错误率: 0.22742474916387959
分类错误率: 0.21739130434782608
分类错误率: 0.22073578595317725
分类错误率: 0.21739130434782608
分类错误率: 0.22408026755852842
分类错误率: 0.22408026755852842
分类错误率: 0.23076923076923078
分类错误率: 0.22408026755852842
分类错误率: 0.2140468227424749
分类错误率: 0.20735785953177258
分类错误率: 0.22408026755852842
分类错误率: 0.22408026755852842
分类错误率: 0.2140468227424749
分类错误率: 0.22073578595317725
分类错误率: 0.2040133779264214
分类错误率: 0.20735785953177258
分类错误率: 0.21070234113712374
分类错误率: 0.21739130434782608
分类错误率: 0.21070234113712374
分类错误率: 0.21739130434782608
分类错误率: 0.20735785953177258
分类错误率: 0.21070234113712374
分类错误率: 0.20735785953177258
分类错误率: 0.20735785953177258
分类错误率: 0.19732441471571907
分类错误率: 0.19063545150501673
分类错误率: 0.20066889632107024
分类错误率: 0.19732441471571907
训练集准确率为: 0.802675585284281
测试集准确率为: 0.8059701492537313
(0.802675585284281, 0.8059701492537313)
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
xMat=np.matrix([[1. ,2.1],
[2. ,1.1],
[1.3,1. ],
[1. ,1. ],
[2. ,1. ]])
yMat=np.mat([[ 1.],
[ 1.],
[-1.],
[-1.],
[ 1.]])
plt.rcParams['font.sans-serif']=['Simhei']
def showPlot(xMat,yMat):
x=np.array(xMat[:,0])
y=np.array(xMat[:,1])
lable=np.array(yMat)
plt.scatter(x,y,c=lable)
plt.title('决策树桩测试数据')
plt.show()
showPlot(xMat,yMat)
def Classify0(xMat,i,Q,S):
re=np.ones((xMat.shape[0],1))
if(S=='lt'):
re[xMat[:,i]<=Q]=-1
elif(S=='gt'):
re[xMat[:,i]>Q]=-1
return re
def get_Stump(xMat,yMat,D):
m,n=xMat.shape
Steps=10
bestStump={}
bestClas=np.mat(np.zeros((m,1)))
minE=np.inf
for i in range(n):
Min=xMat[:,i].min()
Max=xMat[:,i].max()
stepSize=(Max-Min)/Steps
for j in range(-1,int(Steps)+1):
for S in ['lt','gt']:
Q=(Min+j*stepSize)
re=Classify0(xMat,i,Q,S)
err=np.mat(np.ones((m,1)))
err[re==yMat]=0
eca=D.T*err
if(eca<minE):
minE=eca
bestClas=re.copy()
bestStump['特征列']=i
bestStump['阈值']=Q
bestStump['标志']=S
return bestStump,minE,bestClas
def Ada_train(xMat,yMat,maxC):
weakClass=[]
m=xMat.shape[0]
D=np.mat(np.ones((m,1))/m)
aggClass=np.mat(np.zeros((m,1)))
for i in range(maxC):
Stump,error,bestClas=get_Stump(xMat,yMat,D)
alpha=float(0.5*np.log((1-error)/max(error,1e-16)))
Stump['alpha']=np.round(alpha,2)
weakClass.append(Stump)
expon=np.exp(np.multiply(-1*alpha*yMat,bestClas))
D=np.multiply(D,expon)
D=D/D.sum()
aggClass+=alpha*bestClas
Hx=np.sign(aggClass)
aggErr=np.multiply(Hx!=yMat,np.ones((m,1)))
errRate=aggErr.sum()/m
print('分类错误率:',errRate)
if(errRate==0): break
return weakClass,aggClass
weakClass,aggClass=Ada_train(xMat,yMat,40)
print('最佳基学习器:\n',weakClass,'\nH(x)中的累加量:\n',aggClass)
def AdaClassify(data,weakClass):
dataMat=np.mat(data)
m=dataMat.shape[0]
aggClass=np.mat(np.zeros((m,1)))
for i in range(len(weakClass)):
classEst=Classify0(dataMat,weakClass[i]['特征列'],
weakClass[i]['阈值'], weakClass[i]['标志'])
aggClass+=weakClass[i]['alpha']*classEst
return np.sign(aggClass)
print(AdaClassify([0,0],weakClass))
def calAcc(maxC):
dataSetTrain=pd.read_table('E:/AdaBoost/horseColicTraining2.txt',header=None)
train_xMat=np.mat(dataSetTrain.iloc[:,:-1].values)
train_yMat=np.mat(dataSetTrain.iloc[:,-1].values).T
weakClass,aggClass=Ada_train(train_xMat,train_yMat,maxC)
yhat=AdaClassify(train_xMat,weakClass)
trainCorCount=0
m=train_xMat.shape[0]
for i in range(m):
if(yhat[i]==train_yMat[i]):
trainCorCount+=1
trainAcc=trainCorCount/m
print('训练集准确率为:',trainAcc)
testCorCount=0
dataSetTest=pd.read_table('E:/AdaBoost/horseColicTest2.txt',header=None)
test_xMat=np.mat(dataSetTest.iloc[:,:-1].values)
test_yMat=np.mat(dataSetTest.iloc[:,-1].values).T
yhat=AdaClassify(test_xMat,weakClass)
n=test_xMat.shape[0]
for i in range(n):
if(yhat[i]==test_yMat[i]):
testCorCount+=1
testAcc=testCorCount/n
print('测试集准确率为:',testAcc)
return trainAcc,testAcc
print(calAcc(40))
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_gaussian_quantiles
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
x1,y1=make_gaussian_quantiles(cov=2.,n_samples=200,n_features=2,n_classes=2,random_state=1)
#为了增加样本分布的复杂度,再生成一个数据分布
x2,y2=make_gaussian_quantiles(mean=(3,3),cov=1.5,n_samples=300, #两样本特征均值为3和3
n_features=2,n_classes=2,random_state=1)
x=np.concatenate((x1,x2)); y=np.concatenate((y1,-y2+1))
#np.concatenate:默认垂直合并
#x:数据; y:数据集所属类别(两类:0或1)
print('数据集:\n',x,'\n','分类标签:\n',y)
'''make_gaussian_quantiles:生成分组多维正态分布的数据; mean:特征均值(上方默认为(0,0));cov:样本协方差的系数;n_samples:样本个数; n_features:正态分布的维数;n_classe:输出的类别数; n_classe=2:生成的数据按分位数分成2组'''
运行结果
数据集:
[[ 7.00334571e-01 -2.47067578e-01]
[-3.95001869e+00 2.74007953e+00]
[ 1.50221617e-01 -2.15763780e+00]
[-1.67205033e+00 -9.41519069e-01]
... ...
[ 8.94180435e-01 3.06995865e+00]
[ 8.49439078e-01 3.87543489e+00]
[ 5.21744335e+00 1.40081765e+00]]
分类标签:
[0 1 1 1 1 1 1 0 1 1 0 1 1 0 1 1 1 1 1 1 1 0 1 0 0 1 0 0 1 1 0 1 0 1 1 1
... 1 1 0 0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0]
weakClassifier=DecisionTreeClassifier(max_depth=1)
bdt=AdaBoostClassifier(weakClassifier,algorithm="SAMME",n_estimators=200)
#选择SAMME算法,最多200个弱分类器
bdt.fit(x,y) #fit():训练算法,设置内部参数
plt.figure(figsize=(10,5)) #生成10(in)*5(in)=50(in^2)大的空画布
plt.subplot(121)
x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
#上述两行为下面画网格图做准备(控制范围,使数据合理坐落在图中)
plot_step=0.02
xx,yy=np.meshgrid(np.arange(x_min,x_max,plot_step),np.arange(y_min,y_max,plot_step))
Z=bdt.predict(np.c_[xx.ravel(),yy.ravel()])
Z=Z.reshape(xx.shape)
#以上2行,将xx、yy展开,然后预测每个点的类别,将结果大小调整到和坐标数据相同的矩阵大小
cs=plt.contourf(xx,yy,Z,cmap=plt.cm.Paired)
plt.axis('tight') #使坐标轴适应数据量,即有一个范围合理的坐标轴
plt.show()
plt.subplot(121)
''' 将画布大小分成几个部分,参数'121'表示1(row)x2(col),即将画布分成1x2,一行两列的 2块区域,第三个数1表示选择图形输出的区域在第一块,图形输出区域参数必须在"行×列"范 围内,此处必须在1和2之间选择 '''
xx,yy=np.meshgrid(np.arange(x_min,x_max,plot_step),np.arange(y_min,y_max,plot_step))
''' 生成网格点坐标矩阵,在x、y方向上以plot_step逐渐生成 (以0.02的步伐在X坐标上取点,以0.02的步伐在Y坐标上取点) 基本取满坐标中的画布 '''
Z=bdt.predict(np.c_[xx.ravel(),yy.ravel()])
''' np.c_[]:多维数组水平合并,对一维数组放竖再水平合并 np.ravel():将多行的多维数组铺平成一维数组(一行) predict():返回的是一个大小为n的一维数组,用训练好的分类器去预测出()内数据的标签, 一维数组中的第i个值为模型预测第i个预测样本的标签,即在y中的对应值 如: x_train=np.array([[1,2,3],[1,3,4],[2,1,2],[4,5,6],[3,5,3],[1,7,2]]) y_train=np.array([0,0,0,1,1,1]) x_test=np.array([[2,2,2],[3,2,6],[1,7,4]]) clf=LogisticRegression() clf.fit(x_train,y_train) clf.predict(x_test) >>>array([1,0,1]) '''
cs=plt.contourf(xx,yy,Z,cmap=plt.cm.Paired)
''' plt.contourf(X,Y,f(X,Y)),其中X、Y为shape相同的一维数组 plt.cm中cm全称表示colormap,paired表示两个两个相近色彩输出, 比如浅蓝、深蓝;浅红、深红;浅绿,深绿 '''
运行结果
plot_colors='br';class_names='AB'
for i,n,c in zip(range(2),class_names,plot_colors):
idx=np.where(y==i)
plt.scatter(x[idx,0],x[idx,1],color=c,cmap=plt.cm.Paired,
s=20,edgecolor='k',label='Class %s'%n)
plt.xlim(x_min,x_max);plt.ylim(y_min,y_max)
plt.legend(loc='upper right')
plt.xlabel('x'),plt.ylabel('y')
plt.title('Decision Boundary')
plt.show()
idx=np.where(y==i)
''' np.where(condition,x,y),满足条件(condition),输出x,不满足输出y; 若只有条件(condition),没有x和y,则输出满足条件(即非0)元素的坐标,这里的坐标以tuple的形式给出 如: a=np.array([2,4,6,8,10]) np.where(a>5) >>>(array([2,3,4]),) '''
for i,n,c in zip(range(2),class_names,plot_colors):
print(i,n,c)
''' >>> 0 A b 1 B r '''
运行结果
twoclass_output=bdt.decision_function(x) #decision_function(x):计算输入x的决策函数值
plot_range=(twoclass_output.min(),twoclass_output.max())
plt.subplot(122)
for i,n,c in zip(range(2),class_names,plot_colors):
plt.hist(twoclass_output[y==i],bins=10,range=plot_range,facecolor=c,
label='Class %s'%n,alpha=0.5,edgecolor='k')
#bins指定箱子的个数,即总共有几条条状图
x1,x2,y1,y2=plt.axis()
plt.axis((x1,x2,y1,y2*1.2))
#plt.axis([-1,10,0,6]):x轴起始于-1,终止于10,y轴起始于0,终止于6
plt.legend(loc='upper right')
plt.ylabel('Samples');plt.xlabel('Score')
plt.title('Decision Scores')
plt.tight_layout() #tight_layout会自动调整子图参数,使之填充整个图像区域
plt.subplots_adjust(wspace=0.35)
#以上2行都为调整图像边缘及图像间的空白间隔
plt.show()
运行结果
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_gaussian_quantiles
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
#1、创建数据集
x1,y1=make_gaussian_quantiles(cov=2.,n_samples=200,n_features=2,n_classes=2,random_state=1)
x2,y2=make_gaussian_quantiles(mean=(3,3),cov=1.5,n_samples=300,
n_features=2,n_classes=2,random_state=1)
x=np.concatenate((x1,x2)); y=np.concatenate((y1,-y2+1))
#2、创建模型,选择决策树桩为基学习器,并以AdaBoost拟合
weakClassifier=DecisionTreeClassifier(max_depth=1)
bdt=AdaBoostClassifier(weakClassifier,algorithm="SAMME",n_estimators=200)
bdt.fit(x,y)
#3、描绘决策边缘
plt.figure(figsize=(10,5))
plt.subplot(121)
x_min,x_max=x[:,0].min()-1,x[:,0].max()+1
y_min,y_max=x[:,1].min()-1,x[:,1].max()+1
plot_step=0.02
xx,yy=np.meshgrid(np.arange(x_min,x_max,plot_step),np.arange(y_min,y_max,plot_step))
Z=bdt.predict(np.c_[xx.ravel(),yy.ravel()])
Z=Z.reshape(xx.shape)
cs=plt.contourf(xx,yy,Z,cmap=plt.cm.Paired)
plt.axis('tight')
#4、描点
plot_colors='br';class_names='AB'
for i,n,c in zip(range(2),class_names,plot_colors):
idx=np.where(y==i)
plt.scatter(x[idx,0],x[idx,1],color=c,cmap=plt.cm.Paired,
s=20,edgecolor='k',label='Class %s'%n)
plt.xlim(x_min,x_max);plt.ylim(y_min,y_max)
plt.legend(loc='upper right')
plt.xlabel('x'),plt.ylabel('y')
plt.title('Decision Boundary')
#5、描绘两类别得分
twoclass_output=bdt.decision_function(x)
plot_range=(twoclass_output.min(),twoclass_output.max())
plt.subplot(122)
for i,n,c in zip(range(2),class_names,plot_colors):
plt.hist(twoclass_output[y==i],bins=10,range=plot_range,facecolor=c,
label='Class %s'%n,alpha=0.5,edgecolor='k')
x1,x2,y1,y2=plt.axis()
plt.axis((x1,x2,y1,y2*1.2))
plt.legend(loc='upper right')
plt.ylabel('Samples');plt.xlabel('Score')
plt.title('Decision Scores')
plt.tight_layout()
plt.subplots_adjust(wspace=0.35)
plt.show()