算法概述
原理
在无线通信领域,有一种“MIMO”技术。
“MIMO”是什么呢? 它是 多输出多输入 “Multi Iuput Multi Output”的缩写。
它可以用来解决来降低误码率并提升信道容量的问题。
其原理是:通过多个发射机发送的信号,并在多个接收机端接收信号,这些信号经历的衰减是相互独立的。这样一来,在接收端多个信号同时被严重衰减的概率就会以指数形式减小,通过获得分集增益带来误码率的下降与信道容量的提升。
无线通信中的分集思想在机器学习中的对应就是集成学习。集成学习正是使用多个个体学习器来获得比每个单独学习器更好的预测性能。
生成方法
由于机器学习中的个体学习器是为了解决相同的问题而训练出来的,因此要让他们的性能完全独立实在是很强人所难。
并且,当集成结果叠加后,如果仅仅只有某一个个体学习器准确性较高的话,那么集成后的学习器的选择就会陷到一点无法自拔,对其它较弱的学习器的选择就会视而不见。但这就与我们希望集成各种学习器优势的美好愿望相悖。因此,集成学习的核心问题就在于多样性和准确性之间做出折中,来选出具优势的个体学习器,并将他们结合起来。
那么,在选择如何训练个体生成器时,目前的集成学习提供的方法大致可以分为两大类:序列化方法和并行化方法。即就是,如果个体学习器间存在强依赖方式的话,就必须串行训练个体学习器,即就是序列化方法;若个体学习器间不存在强依赖关系、可并行训练个体学习器、即就是并行化方法。
序列化生成方法的代表算法就是Boosting,其中的典型为:AdaBoost。并行化生成方法的代表就是Bagging、随机森林。
序列化生成方法是一种迭代训练的过程,通过在每一次迭代中通过重新赋予权重对基学习器继续训练,最后将每次改变权值后的训练的学习机结合。并行化生成方法,一般是基于自主采样法,即就是随机从数据集中抽取出一定的样本,再将数据放回,得到多个采样集,然后基于每个采样集训练出一个基学器,再将这些基学习器进行结合(集成)。
不管是序列化生成中所使用的重赋权值,还是并行化生成方法中的随机采样,其目的都是在于,通过人为干预来使个体学习机达到提取不同维度特征的功能,在一定程度上保持基学习器每次训练过程中的独立性。
集成方法
在个体学习器训练完后,我们就要考虑,将基学习器进行集成。
学习器的集成会从三个方面带来好处:首先,降低学习空间过大的情况下,单个学习器因种种愿意可能导致的泛化性能不佳的问题。其次,通过多次训练之后进行结合,可降低在计算过程中陷入糟糕局部极小点的风险;最后,集成后,学习任务的假设空间有所扩大,有可能会学得对真是空间更好的近似。
平均法、投票法、学习法都是对学习器集成常见的策略。这里就先不提。
集成以后,我们可以对集成学习器的做多样性度量,若是多样性不足,我们还可以采用数据样本扰动等方法来进行多样性增强。
代码设计
接下来,我们将会使用一个集成学习的方法Adaboost来实现一个使用SVM作为基学习器的二分类的集成学习。
数据处理
测试数据集使用MUSK麝香数据集。数据集地址连接: http://archive.ics.uci.edu/ml/datasets/Musk+(Version+2)
使用以下代码对其进行处理:、
def loadData2(filename):
fr = open(filename)
numFeat = len(fr.readline().strip().split(','))-1 # 读取行数 并做处理 返回的值 是各方数据的个数的列表
dataMat = []
labelMat = []
for line in fr.readlines():
lineArr = []
curline = line.strip().split(',') # 数据的操作
for i in range(numFeat):
lineArr.append(float(curline[i+1])) # 行向量
dataMat.append(lineArr)
labelMat.append(float(curline[0]))
return dataMat, labelMat # 生成数据和标签
基学习器的实现
基学习器使用支持向量机来实现,,基于skit-learn分别使用3个不同的核函数 linear、RBF、SIGMOD。
定义不同的核函数,来尝试提取不同方向上的特征。
class svmLearn:
def __init__(self, x, y):
# x和y的矩阵
self.xArr = x
self.yArr = y
# 根据集合分开训练集和测试集
rowNum = len(y)
singleNum = math.ceil(rowNum / 5)
testNum = singleNum * 4
self.TestXarr = []
self.TestYarr = []
self.TrainXarr = []
self.TrainYarr = []
trainNum = rowNum - testNum
for i in range(int(singleNum)): # 生成5份相关测试和结果
if 5 * i >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i])
self.TrainYarr.append(y[5 * i])
if 5 * i + 1 >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i + 1])
self.TrainYarr.append(y[5 * i + 1])
if 5 * i + 2 >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i + 2])
self.TrainYarr.append(y[5 * i + 2])
if 5 * i + 3 >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i + 3])
self.TrainYarr.append(y[5 * i + 3])
if 5 * i + 4 >= rowNum - 1:
break
self.TestXarr.append(x[5 * i + 4])
self.TestYarr.append(y[5 * i + 4])
'''self.TestXarr = x[0:testNum][:]
self.TrainXarr = x[testNum: rowNum][:]
self.TestYarr = y[0:testNum]
self.TrainYarr = y[testNum:rowNum]'''
def linearSVM(self):
# print numpy.shape(self.TrainXarr)
bestResult = 0
besti = 0
bestj = 0
plotx = [0] * 100
ploty = [0] * 100
plotz = [0] * 100
index = 0
for i in range(10):
for j in range(10):
linear_svc = svm.SVC(kernel='linear', C=10 ** (i - 5), gamma=10 ** (j - 5))
# linear_svc.fit(self.TrainXarr, self.TrainYarr)
# yPredict = linear_svc.predict(self.TestXarr)
# print diff1(yPredict, self.TestYarr) / float(len(yPredict))
# print len(yPredict)
scores = model_selection.cross_val_score(linear_svc, self.TrainXarr, self.TrainYarr, cv=5)
# print i, j
# print scores
plotx[index] = i - 5
ploty[index] = j - 5
plotz[index] = scores.mean()
index += 1
if scores.mean() > bestResult:
bestResult = scores.mean()
besti = i
bestj = j
print(bestResult)
print(besti)
print(bestj)
linear_svc = svm.SVC(kernel='linear', C=10 ** (besti - 5), gamma=10 ** (bestj - 5)) # 设置支持向量机分类器
linear_svc.fit(self.TrainXarr, self.TrainYarr)
yPredict = linear_svc.predict(self.TestXarr)
print('测试集正确率:')
print(diff1(yPredict, self.TestYarr) / float(len(yPredict)))
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_trisurf(plotx, ploty, plotz, cmap=cm.jet, linewidth=0)
plt.xlabel('C:')
plt.ylabel('gamma:')
plt.show()
def rbfSVM(self):
bestResult = 0
besti = 0
bestj = 0
plotx = [0] * 100
ploty = [0] * 100
plotz = [0] * 100
index = 0
for i in range(10):
for j in range(10):
linear_svc = svm.SVC(kernel='rbf', C=10 ** (i - 5), gamma=10 ** (j - 5))
scores = model_selection.cross_val_score(linear_svc, self.TrainXarr, self.TrainYarr, cv=5)
# print i,j
# print scores
plotx[index] = i - 5
ploty[index] = j - 5
plotz[index] = scores.mean()
index += 1
if scores.mean() > bestResult:
bestResult = scores.mean()
besti = i
bestj = j
print(bestResult)
print(besti)
print(bestj)
linear_svc = svm.SVC(kernel='rbf', C=10 ** (besti - 5), gamma=10 ** (bestj - 5))
linear_svc.fit(self.TrainXarr, self.TrainYarr)
yPredict = linear_svc.predict(self.TestXarr)
print('测试集正确率:')
print(diff1(yPredict, self.TestYarr) / float(len(yPredict)))
fig = plt.figure()
ax = fig.gca(projection='3d')
# ax.plot_trisurf(plotx, ploty, plotz)
ax.plot_trisurf(plotx, ploty, plotz, cmap=cm.jet, linewidth=0.2)
# ax.plot_surface(plotx, ploty, plotz, rstride=1, cstride=1, cmap='rainbow')
plt.xlabel('C:')
plt.ylabel('gamma:')
plt.show()
def sigmoidsvm(self):
bestResult = 0
besti = 0
bestj = 0
plotx = [0] * 100
ploty = [0] * 100
plotz = [0] * 100
index = 0
for i in range(10):
for j in range(10):
linear_svc = svm.SVC(kernel='sigmoid', C=10 ** (i - 5), gamma=10 ** (j - 5))
scores = model_selection.cross_val_score(linear_svc, self.TrainXarr, self.TrainYarr, cv=16)
plotx[index] = i - 5
ploty[index] = j - 5
plotz[index] = scores.mean()
index += 1
if scores.mean() > bestResult:
bestResult = scores.mean()
besti = i
bestj = j
print(bestResult)
print(besti)
print(bestj)
linear_svc = svm.SVC(kernel='sigmoid', C=10 ** (besti - 5), gamma=10 ** (bestj - 5))
linear_svc.fit(self.TrainXarr, self.TrainYarr)
yPredict = linear_svc.predict(self.TestXarr)
print('测试集正确率:')
print(diff1(yPredict, self.TestYarr) / float(len(yPredict)))
fig = plt.figure()
ax = fig.gca(projection='3d')
# ax.plot_trisurf(plotx, ploty, plotz)
ax.plot_trisurf(plotx, ploty, plotz, cmap=cm.jet, linewidth=0.2)
# ax.plot_surface(plotx, ploty, plotz, rstride=1, cstride=1, cmap='rainbow')
plt.xlabel('C:')
plt.ylabel('gamma:')
plt.show()
定义adaboost
基于adaboost序列化学习器生成方法,定义序列化生成步骤。代码如下:
class Adaboost():
def __init__(self, numOfInter, x, y):
self.xArr = x
self.yArr = y
# 根据集合分开训练集和测试集
rowNum = len(y)
singleNum = math.ceil(rowNum / 5) # 返回x上限作为一个积分
testNum = singleNum * 4
self.TestXarr = []
self.TestYarr = []
self.TrainXarr = []
self.TrainYarr = []
trainNum = rowNum - testNum
for i in range(int(singleNum)): # 初始化样本权重分布
if 5 * i >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i]) #
self.TrainYarr.append(y[5 * i])
if 5 * i + 1 >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i + 1])
self.TrainYarr.append(y[5 * i + 1])
if 5 * i + 2 >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i + 2])
self.TrainYarr.append(y[5 * i + 2])
if 5 * i + 3 >= rowNum - 1:
break
self.TrainXarr.append(x[5 * i + 3])
self.TrainYarr.append(y[5 * i + 3])
if 5 * i + 4 >= rowNum - 1:
break
self.TestXarr.append(x[5 * i + 4])
self.TestYarr.append(y[5 * i + 4])
self.NumofClassifier = numOfInter
def AdaboostTrain(self, wk_list, x, y):
NumofData = numpy.shape(x)[0]
# typelist = ['linear', 'rbf','sigmoid']
typelist = wk_list
g_list = [] # 弱分类器的权重
weight_array = numpy.zeros((NumofData, 1))
weight_array[:, 0] = 1.0 / NumofData
for t in range(self.NumofClassifier): # 基于分布训练不同的分类器
min_err_rate = 1
temp_weight = []
g = []
for w in wk_list:
print(w)
# 分类器的类型
# type = typelist[w[0]]
type = w
para_c = w[1]
para_gamma = w[2]
# svmp = svm.SVC(kernel = type, C = para_c,gamma = para_gamma)
svmp = svm.SVC(kernel=type)
svmp.fit(x, y, sample_weight=weight_array[:, 0]) # 首先先训练出一个基学习器
prediction = svmp.predict(x)
err_rate = sum(weight_array[prediction != y])
err_rate = err_rate / sum(weight_array)
if err_rate == 0: # 再对基学习器表现对训练样本的分布进行调整
g_list = []
# g.append(w[0])
# g.append(w[1])
# g.append(w[2])
# g.append(1)
# g_list.append(g)
g.append(typelist.index(w))
g.append(1)
return g_list
if err_rate < min_err_rate:
min_err_rate = err_rate
best_prediction = prediction
besttype = typelist.index(type)
best_c = para_c
best_pamma = para_gamma
print(min_err_rate)
if min_err_rate > 0.5: # 检查当前生成的分类器效果是否比基分类器好
print('error rate is larger than 0.5')
return g_list
alpha = 0.5 * numpy.log((1 - min_err_rate) / min_err_rate) # 使基学习器做错的训练在后续受到更多的关注
g.append(besttype)
g.append(alpha)
g_list.append(g)
# 更新权重
weight_array[best_prediction == y] = weight_array[best_prediction == y] * numpy.exp(-alpha) # 降低正确的权重
# 基于调整后的分布来训练下一个基学习器
weight_array[best_prediction != y] = weight_array[best_prediction != y] * numpy.exp(alpha) # 增加错误权重
weight_array = weight_array / sum(weight_array) # 将不同的训练器的效果按照一定比例加起来
return g_list
def AdaboostTest(self, g_list, xTest, xTrain, yTrain, type_list):
N = numpy.shape(xTest)[0]
typelist = type_list
alpha_array = [0] * N
for g in g_list:
type = typelist[g[0]]
# svmp = svm.SVC(kernel = type , C = 0.01, gamma = para_gamma)
svmp = svm.SVC(kernel=type)
print(numpy.shape(xTrain))
print(numpy.shape(yTrain))
svmp.fit(xTrain, yTrain)
prediction = svmp.predict(xTest)
alpha_array = alpha_array + prediction * g[1]
return alpha_array
集成分类器
集成基学习器的学习效果,这里注意,可以对弱学习器分类效果,小于概率0.5的予以舍弃。
def diff1(y1, y2): #
right = 0
length = len(y1)
for i in range(length):
if y1[i] >= 0.5 and y2[i] >= 0.5:
# and 表示从左到右计算表达式,若所有值均为真,则返回最后一个值,若存在假,返回第一个假值
right += 1
if y1[i] < 0.5 and y2[i] < 0.5:
right += 1
return right
结果
基分类器的学习效果如下:
集成学习结果
源码地址: