python 实现AdaBoost 算法

有用请点赞,没用请差评。

欢迎分享本文,转载请保留出处。

 

 目前程序的训练部分分类器部分没有问题,但是最后的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
        2) 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<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_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,不够好。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值