adaboost实现
不知道为什么自己写的adaboost代码运行的错误率随着迭代次数增加的曲线很奇怪,经常在迭代次数=1的时候错误率最低
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
class AdaBoostClassifier:
def __init__(self, M, base_clf): # 创建一个 AdaBoost 分类器的类
self.M = M # 记录迭代次数
self.base_clf = base_clf # 记录基分类器
def fit(self, X_train, Y_train): # 定义 fit 方法用于训练模型
n_train = len(X_train) # 获取训练样本的数量
self.w = np.ones(n_train) / n_train # 初始化样本权重,使其总和为1,用于加权训练
self.classifiers = [] # 初始化分类器列表
self.alphas = [] # 初始化分类器权重列表
self.t = 1
# 开始进行迭代训练
while self.t <= self.M:
clf = self.base_clf # 创建基分类器的实例
clf.fit(X_train, Y_train, sample_weight=self.w) # 使用样本权重进行训练 #基础分类器需要支出样本权重
pred_train_i = clf.predict(X_train) # 对训练集进行预测
miss = (pred_train_i != Y_train) # 判断预测结果是否与真实标签不符
err_m = np.dot(self.w, miss)
#print(f"第{self.t}次迭代,当前弱分类器的带权训练误差率:{err_m}") #打印每次迭代的训练误差率和迭代次数
alpha_m = float(0.5 * np.log((1 - err_m) / max(err_m, 1e-16))) # 计算当前分类器的权重
#print(f"----------------{self.t}轮迭代的权重和:{sum(self.w)}")
Z_m = sum((np.multiply(self.w, np.exp(-alpha_m * pred_train_i * Y_train )))) # 规范化因子
self.w = np.multiply(self.w, np.exp(-alpha_m * pred_train_i * Y_train))/ Z_m # 更新样本权重
self.classifiers.append(clf) # 将当前分类器加入分类器列表
self.alphas.append(alpha_m) # 将当前分类器的权重加入权重列表
pred_train = self.predict(X_train) # 对训练集进行预测
miss2 = (pred_train != Y_train) # 预测错误则为True
miss_sample_sum_num2 = np.sum(miss2) # 分类错误样本总个数
if miss_sample_sum_num2 == 0:
print(f"第{self.t}次迭代,集合的强分类器误差率已经达到0,结束迭代。")
break
self.t += 1
def predict(self, X): # 定义预测方法
n_samples = len(X) # 获取样本数量
pred = np.zeros(n_samples) # 初始化预测结果数组
# 对每个分类器和权重进行迭代
for alpha, clf in zip(self.alphas, self.classifiers):
pred += alpha * clf.predict(X) # 加权累加预测结果
return np.sign(pred) # 对预测结果进行符号化处理,返回预测标签数组
#制造随机数据
from sklearn.datasets import make_classification
num_samples = 500 # 设置样本数量
num_features = 33 # 设置特征数量
# 生成二分类数据集
dataMat, labelMat= make_classification(
n_samples=num_samples,
n_features=num_features,
n_informative=num_features-3,
n_redundant=3, #表示冗余特征的数量,这些特征与信息特征线性相关。
n_clusters_per_class=1, #表示每个类别内部的簇数
flip_y=0., #表示标签翻转的概率,用于模拟部分噪声
random_state=42
)
labelMat = np.where(labelMat == 0, -1, labelMat) #把数组的0变成-1
# # 绘制数据集
# plt.scatter(dataMat[:, 0], dataMat[:, 1], c=labelMat, cmap='bwr')
# plt.xlabel('Feature 1') # x轴标签
# plt.ylabel('Feature 2') # y轴标签
# plt.title('Randomly Generated Dataset') # 图表标题
# plt.show()
#拆分测试集
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(dataMat, labelMat, test_size=0.3,
random_state=42) # 拆分数据20%作为测试的
flip_ratios = 0.0 #噪声比例
flip_count = int(flip_ratios * len(Y_train))
flip_indices = np.random.choice(len(Y_train), flip_count, replace=False)
Y_train_flip = np.copy(Y_train)
Y_train_flip[flip_indices] *= -1
#========================================================================================================================
from sklearn.tree import DecisionTreeClassifier
base_clf = DecisionTreeClassifier(max_depth=1)
#创建adaboost
adaboost = AdaBoostClassifier(M=20, base_clf= DecisionTreeClassifier(max_depth=1))
adaboost.fit(X_train,Y_train_flip)
print(f"弱分类器个数:{len(adaboost.classifiers)}")
# 评估分类器
from sklearn.metrics import accuracy_score
train_predictions = adaboost.predict(X_train)
test_predictions = adaboost.predict(X_test)
train_error_rate = 1 - accuracy_score(Y_train, train_predictions, normalize=True, sample_weight=None)
test_error_rate = 1 - accuracy_score(Y_test, test_predictions, normalize=True, sample_weight=None)
print(f"噪声比例:{flip_ratios*100}%")
#错误率
print("训练误差:", train_error_rate)
print("测试误差:", test_error_rate)
base_clf.fit(X_train,Y_train_flip)
train_pre = base_clf.predict(X_train)
miss = sum(train_pre != Y_train) / len(Y_train)
print(f"单个基础分类器的训练误差率 = {miss}")
train_pre2 = base_clf.predict(X_test)
miss2 = sum(train_pre2 != Y_test) / len(Y_test)
print(f"单个基础分类器的测试误差率 = {miss2}")