有用请点赞,没用请差评。
欢迎分享本文,转载请保留出处。
目前程序的训练部分分类器部分没有问题,但是最后的predict部分还存在点问题,一直没有找出来,等有时间了再来修改吧。
采用的数据集:github:https://github.com/Tomator01/-Machine-Learning
# -*- coding:utf-8 -*-
# AdaBoost算法
# author:Tomator
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
import cv2
import time
import math
class AdaBoost(object):
def __init__(self, epsilon=0.0):
# 暂时没有加上epsilon,也可以加上
self.epsilon = epsilon # 分类误差率阈值
self.w = None # 样本的权值,每加入一个基本分类器都要重新计算
self.N = None
self.alpha = [] # 基本分类器前面的系数
def init_param(self, X_data):
# 初始化参数,包括权值和所有可能的弱分类器
self.N = X_data.shape[0] #训练数据样本数
self.features_n=X_data.shape[1] #特征维度数
self.w = np.ones(self.N) / self.N # 初始化权值
self.M = 10 #最大弱分类器数目
self.classifier = [] # (维度,分类器),针对当前维度的分类器
def _Z_(self,index,classifier,X_data,y_data):
'''
公式8.5
Z是规范化因子
'''
Z = 0
for i in range(self.N):
Z += self._w_(index,classifier,i,X_data,y_data)
return Z
def _w_(self,index,classifier,i,X_data,y_data):
return self.w[i] * math.exp(-self.alpha[-1] * y_data[i] * classifier.predict(X_data[i][index]))
def cal_alpha(self, err):
# 计算基本分类器前的系数
return 1.0 / 2 * math.log((1 - err) / err)
def cal_weight(self, X_data, y_data,best_classifier,Z):
# 更新每个样本权重
for i in range(self.N):
self.w[i] = (self.w[i]*self._w_(best_classifier[1], best_classifier[2], i,X_data,y_data)) / Z
return self.w
# 训练
def fit(self, X_data, y_data):
# 初始化
self.init_param(X_data)
# print("features_n",self.features_n)
for m in range(self.M): # 逐步添加基本分类器
best_classifier = (100000, None, None) # (误差率,针对的特征维度位置,分类器)
for i in range(self.features_n):
classifier=Sign(X_data[:,i], y_data,self.w) #寻找每一维度的最优弱分类器,X_data[:,i]数据向量的某一维度的数据
error_score=classifier.train() #返回最小误差率
#选出误差率最小的弱分类器
if error_score < best_classifier[0]:
best_classifier = (error_score,i,classifier)
# print("training index:",best_classifier[1],m)
# 将每一次的弱分类的对象存放在self.classifier中
self.classifier.append(best_classifier[1:])
# 计算弱分类器Gm(x)前的系数
if best_classifier[0]==0:
print("error is zero")
self.alpha.append(100)
else:
alpha = self.cal_alpha(best_classifier[0])
self.alpha.append(alpha) # 基本分类器前面的系数
print("error:", best_classifier[0], " alpha:", self.alpha[-1])
# Z是规范化因子
Z=self._Z_(best_classifier[1],best_classifier[2],X_data,y_data)
# 更新权值
self.w=self.cal_weight(X_data, y_data,best_classifier,Z)
print("train over")
return
def predict(self, X):
# 预测
result = 0.0
# 循环每一个分类器
for i in range(self.M):
# index为每一个弱分类器的分类维度坐标
index = self.classifier[i][0]
# print("classifier index: %d"%index)
# 每一个弱分类器的分类器对象
classifier = self.classifier[i][1]
# 公式8.7
result += self.alpha[i]*classifier.predict(X[index])
if result>=0:
return 1
return -1
#阈值分类器只能分类单一维度的特征,而通常情况下我们的特征都是多维的,假设特征有n维,我们针对每一维特征求一个分类器,选取这些分类器中分类误差率最低的分类器作为本轮的分类器,将其特征坐标与分类器一起存入G(x)中。
class Sign(object):
'''
阈值分类器
有两种方向,
1)x
v y=1
v 是阈值轴
因为是针对已经二值化后的MNIST数据集,所以v的取值只有2个 {0,1,},
y为label,取值为(1,0),对应于标签化后取值为(1,-1),
'''
def __init__(self,features,labels,w):
self.X = features # 训练数据特征
self.Y = labels # 训练数据的标签
self.N = len(labels) # 训练数据大小
self.w = w # 训练数据权值分布
self.indexes = [0,1] # 阈值轴可选范围
def _train_less_than_(self):
'''
寻找(x
< error_score:
index = i
error_score = score
return index,error_score
def _train_more_than_(self):
'''
寻找(x>v y=1)情况下的最优v
'''
index = -1
error_score = 1000000
for i in self.indexes:
score = 0
for j in range(self.N):
if self.X[j]>=i:
# 对应与laebl为1
if self.Y[j] !=1 :
score += self.w[j]
else:
# 对应与laebl为0
if self.Y[j] != -1:
score += self.w[j]
if score < error_score:
index = i
error_score = score
return index,error_score
def train(self):
less_index,less_score = self._train_less_than_()
more_index,more_score = self._train_more_than_()
if less_score < more_score:
self.is_less = True
self.index = less_index
return less_score
else:
self.is_less = False
self.index = more_index
return more_score
def predict(self,feature):
# 通过弱分类进行预测
if self.is_less == True:
if feature<=self.index:
return 1
else:
return -1
else:
if feature >= self.index:
return 1
else:
return -1
# 图像二值化
def binaryzation(img):
#注意如果机器是老版本的opencv.cv2此处写法会有不同
cv_img = img.astype(np.uint8)
cv2.threshold(cv_img,50,1,cv2.THRESH_BINARY_INV,cv_img)
return cv_img
def binaryzation_features(trainset):
features = []
for img in trainset:
img = np.reshape(img,(28,28))
cv_img = img.astype(np.uint8)
img_b = binaryzation(cv_img)
features.append(img_b)
features = np.array(features)
features = np.reshape(features,(-1,784))
return features
if __name__ == "__main__":
raw_data = pd.read_csv('D://python3_anaconda3//学习//机器学习//机器学习数据集//MNIST数据集——两类label//train_binary.csv', header=0,engine='python')
data = raw_data.values
imags = data[0::, 1::]
features = binaryzation_features(imags)
labels = data[::, 0]
# 划分训练集、测试集
x_train_vector, x_test_vector,x_train_label,x_test_label = train_test_split(features,labels, test_size=0.3, random_state=0)
# print(x_train_label.shape,x_test_vector.shape,x_train_label.shape,x_test_label.shape)
adaboost=AdaBoost()
adaboost.fit(x_train_vector,x_train_label)
score=0
test_nums=x_test_vector.shape[0]
x_test_label = map(lambda x: 2 * x - 1, x_test_label)
for vector,label in zip(x_test_vector,x_test_label):
pred=adaboost.predict(vector)
if pred != label:
score+=1
print("accuracy score is :%f"%(1-score/test_nums))
以上是训练结果,可以看出每次的弱分类器的错误率都在呈指数逐渐降低,相反的是每个弱分类器前的系数是在相应的变大,与adaboost的理论符合,证明train部分是对的。准确率只有为0.895,不够好。