1.AdaBoost算法详解和数学求解过程
AdaBoost强分类器算法的生成过程详解、以及示例讲解数学求解的详细过程,可以详见上篇博客:
https://blog.csdn.net/u012421852/article/details/80201506
2.AdaBoost算法的Python实现
2.0python知识点
代码中主要用到的重要python知识点有:
1)lambda(函数) + np.frompyfunc(函数向量化)
函数向量化可详见:【机器学习】【Numpy】函数向量化运算的4种方法(numpy.frompyfunc()和numpy.vectorize())
2)function + np.frompyfunc
3)np.multiply(序列1, 序列2),实现序列1和序列2的内部下标对应的元素相乘
知识点可详见:【Python】【numpy-汇总5】所有多元计算函数的示例代码
4)lambda + [for 序列A] 可以对序列A中每个元素都进行lambda操作
5)list.count(e) :计算list中元素e的个数
6)sum(list):计算list的所有元素之和
7)ndarray.sum():计算array的所有元素之和
上面5~7详见:【再回首Python之美】【numpy】矩阵matrix、array、list操作示例汇总
8)序列的切片A[0:-1] :不要A的最后(-1)一个元素剩下的切片,如A=[4,5,6,7,8],则A[0:-1] = A[:-1] = [4,5,6,7]
知识点可详见:【Python】【numpy-汇总8】numpy.ndarray索引/切片方式的示例代码
9)(condition then [result1] or [resultt2])[0]
千万不要使用cond then r1 or r2,原因详见:【再回首Python之美】【and-or】危险的and-or,安全的if-else,和安全的and-or
10)生成一个序列,并指定元素的默认值
比如[0.1, 0.1, 0.1, 0.1],可以如下生成:
可知元素默认值为0.1,序列长度N=4
方法1)ret = np.ones((1,N)) / N,生成对象类型为np.ndarray
方法2)ret = [0.1 for e in range(N)],生成对象类型为list
2.2此代码对应看的示例
此代码看时可以对应着下面示例来理解

2.3代码
完全人肉出品,代码详见如下:
# -*- coding: utf-8 -*-
"""
@author:蔚蓝的天空tom
Aim:向量法实现AdaBoost算法
"""
import numpy as np
class CAdaBoost(object):
'''AdaBoost算法'''
def __init__(self, train_samples):
self.S = train_samples #训练样本集
self.N = np.shape(self.S)[0]#样本总数
self.V = [] #所有可能阈值的集合
self.G = [] #分类器的分类结果
self.W = [] #权值分布,/85 weight distribution
self.E = [] #误差率,根据分类器的分类结果计算得到
self.A = [] #分类器的系数,根据误差率e计算得到
self.Z = [] #规范化因子,根据W,A,S[:,-1],G
self.Gen = [] #sign[f(x)]中子分类器的存储,每个子分类器=[系数alpha, 阈值v, f1, f2]
self.init_v()
self.build_generator()
return
def init_v(self):
'''所有可能阈值的集合'''
F = self.S[:,-1] #训练样本集的标签集合
#初始化阈值集合self.V
e_func = lambda i: (F[i] != F[i+1]) \
and self.V.append([i+0.5, F[i],F[i+1]]) \
or None
func = np.frompyfunc(e_func, 1, 1)
ar = np.arange(self.N)[0:-1]#切片:不包含最后一个元素
func(ar)
return self.V
def build_generator(self):
'''迭代生成分类器'''
datas, flags, N, V = self.S[:,0], self.S[:,-1], self.N, self.V
#基本分类器, if x<v then f1 elif x>v then f2
base_gen = lambda x,v,f1,f2 : ((x<v) and [f1] or [f2])[0]
#分类结果错误标记方法, 如果分类结果不等于观测值,则在分类结果错误统计表stat中置1
dif_ufunc = lambda gen_f,observed_f : (gen_f != observed_f and [1] or [0])[0]
dif_func = np.frompyfunc(dif_ufunc, 2, 1)
#初始化权值都为1/N
if np.shape(self.Gen)[0] == 0:
self.W = np.ones((1,N))/N
#遍历访问阈值集合,选取误差率最小的阈值作为最优阈值
G, e, v, f1, f2 = [], 1, None, None, None
for i in range(np.shape(V)[0]):
#分类
cur_G = [base_gen(x, V[i][0], V[i][1], V[i][2]) for x in datas]
#误差率
stat = dif_func(flags, cur_G)
e_dist = np.multiply(stat, self.W)[0]
cur_e = e_dist.sum()
#选取最小误差率
if cur_e<e:
G, e, v, f1, f2 = cur_G, cur_e, V[i][0], V[i][1], V[i][2]
#分类器的系数alpha
alpha = 0.5*np.log((1-e)/e)
#规范化因子z
z_ufunc = lambda w,y,g : w*np.exp(-1*alpha*y*g)
z_func = np.frompyfunc(z_ufunc, 3, 1)
z = z_func(self.W, flags, G).sum()
#更新训练数据的权值分布
w_ufunc = lambda w,y,g : w/z * np.exp(-1*alpha*y*g)
w_func = np.frompyfunc(w_ufunc, 3, 1)
self.W = w_func(self.W, flags, G)
#更新强分类器sign[f(x)]中的f(x)
self.Gen.append([alpha, v, f1, f2]) #系数alpha, 阈值v, f1, f2
#判断是否结束分类器的迭代生成
fx_ufunc = lambda x : sum([g[0]*base_gen(x, g[1], g[2], g[3]) for g in self.Gen])
fx_func = np.frompyfunc(fx_ufunc, 1, 1)
G = np.sign(fx_func(datas))
error_stat = dif_func(flags, G)
error_cnt = list(error_stat).count(1)
if 0 == error_cnt:
print('sign[f(x)]误差个数是0, 成功生成分类器\nsign[f(x)], f(x)=')
print(np.array(self.Gen))
return self.Gen
else:
print('sign[f(x)]误差个数是%d'%list(error_stat).count(1),',需要继续迭代生成分类器.\n')
return self.build_generator()
def Generator(self, test_samples):
'''对测试样本集进行分类'''
#基本分类器 if x<v then f1 elif x>v then f2
base_gen = lambda x,v,f1,f2 : ( x<v and [f1] or [f2])[0]
#f(x)
fx_ufunc = lambda x : sum([g[0]*base_gen(x, g[1], g[2], g[3]) for g in self.Gen])
fx_func = np.frompyfunc(fx_ufunc, 1, 1)
#sign[f(x)]对测试样本集分类
G = np.sign([fx_func(test_samples)])
print('\n测试样本集:', test_samples)
print('分类结果:', G)
return G
def CAdaBoost_manual():
#训练样本集
samples = np.array([[0,1],[1,1],[2,1],[3,-1],[4,-1],[5,-1],[6,1],[7,1],[8,1],[9,-1]])
ab = CAdaBoost(samples) #AdaBoost Algorithm
#用训练样本作为测试样本看看分类器的分类结果
ab.Generator(samples[:,0])
#新建测试样本集看看分类器的结果
test_samples = np.array([0.5,1.5,2.5,3.5,4.5,6.5,7.5,8.5,9.5])
ab.Generator(test_samples)
test_samples = np.array([-5,-4,-3,-2,-1])
ab.Generator(test_samples)
test_samples = np.array([10,11,12,13,14,15])
ab.Generator(test_samples)
if __name__=='__main__':
CAdaBoost_manual()
2.4运行结果
sign[f(x)]误差个数是3 ,需要继续迭代生成分类器.
sign[f(x)]误差个数是3 ,需要继续迭代生成分类器.
sign[f(x)]误差个数是0, 成功生成分类器
sign[f(x)], f(x)=
[[ 0.42364893 2.5 1. -1. ]
[ 0.64964149 8.5 1. -1. ]
[ 0.7520387 5.5 -1. 1. ]]
测试样本集: [0 1 2 3 4 5 6 7 8 9]
分类结果: [[1 1 1 -1 -1 -1 1 1 1 -1]]
测试样本集: [ 0.5 1.5 2.5 3.5 4.5 6.5 7.5 8.5 9.5]
分类结果: [[1 1 -1 -1 -1 1 1 -1 -1]]
测试样本集: [-5 -4 -3 -2 -1]
分类结果: [[1 1 1 1 1]]
测试样本集: [10 11 12 13 14 15]
分类结果: [[-1 -1 -1 -1 -1 -1]]
3.解释上面程序生成的分类器
3.1 训练样本集
train_samples = np.array([[0,1],
[1,1],
[2,1],
[3,-1],
[4,-1],
[5,-1],
[6,1],
[7,1],
[8,1],
[9,-1]])
训练数据=[0,1,3,4,5,6,7,8,9]
训练数据的标记集合=[1,1,1,-1,-1,-1,1,1,1,-1]
3.2 f(x) of sign[f(x)]
sign[f(x)], f(x)=
[[ 0.42364893 2.5 1. -1. ]
[ 0.64964149 8.5 1. -1. ]
[ 0.7520387 5.5 -1. 1. ]]
3.3sign[f(x)]的数学公式代码
sign[f(x)]的数学函数代码为:
def Generator(self, test_samples):
'''对测试样本集进行分类'''
#基本分类器 if x<v then f1 elif x>v then f2
base_gen = lambda x,v,f1,f2 : ( x<v and [f1] or [f2])[0]
#f(x)
fx_ufunc = lambda x : sum([g[0]*base_gen(x, g[1], g[2], g[3]) for g in self.Gen])
fx_func = np.frompyfunc(fx_ufunc, 1, 1)
#sign[f(x)]对测试样本集分类
G = np.sign([fx_func(test_samples)])
print('\n测试样本集:', test_samples)
print('分类结果:', G)
return G
上面代码解释如下:
最终分类器sign[f(x)] = f1(x) + f2(x) + f3(x)
base_gen(x,v,f1,f2) = if x<v then f1 else then f2 #base generator
每一个(fx) = a*bg(x, v, f1, f2)
其中self.Gen[i]存储的是第i个函数f(x)的a, v, f1, f2
则第i个fx, fi(x) = self.Gen[i][0] * base_gen(x, self.Gen[i][1], self.Gen[i][2], self.Gen[i][3])
最终的分类器sign[f(x)] = f1(x) + f2(f) + f3(x)
= sign[0.42364893 * base_gen(x, 2.5, 1, -1) +0.64964149 * base_gen(x, 8.5, 1, -1) + 0.7520387 * base_gen(x, 5.5, -1, 1)]
3.4示例:给样本x=3.5分类
样本x=3.5,分类结果就是:sign[f(x)] = sign[f(3.5)] = sign[-0.526046136517] = -1
再瞅瞅训练样本集:samples = np.array([[0,1],[1,1],[2,1],[3,-1],[4,-1],[5,-1],[6,1],[7,1],[8,1],[9,-1]])
可以知道:3.5被分类到-1,是合理的。
(end)
本文详细介绍了AdaBoost算法的原理和数学求解过程,并提供了完整的Python实现代码,包括关键知识点的解释和运行结果。通过示例解释了训练样本集、分类器的f(x)以及sign[f(x)]的计算,帮助读者深入理解AdaBoost算法。

2444

被折叠的 条评论
为什么被折叠?



