30天打牢数模基础-AdaBoost讲解
案例代码实现
一、代码说明
本代码以信用卡欺诈检测为背景,实现了AdaBoost算法的核心逻辑(权重更新、弱分类器组合)。通过模拟不平衡数据(8个正常交易、2个欺诈交易),展示了AdaBoost如何“专注难样本”(欺诈样本)并通过“集体智慧”提高检测准确率。
适用场景:数模中的二分类问题(如欺诈检测、客户流失预测、疾病诊断等)。核心步骤:
初始化样本权重(每个样本同等重要);
循环训练弱分类器(决策树桩,max_depth=1);
计算弱分类器的加权错误率和“投票权”;
更新样本权重(误分类样本权重升高);
组合所有弱分类器(加权求和取符号)。
二、完整Python代码
import numpy as np
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, confusion_matrixclass AdaBoost:"""AdaBoost算法实现(二分类)参数:n_estimators: 弱分类器数量(默认5)属性:estimators: 保存弱分类器及反转标志((clf, reverse))alpha: 保存弱分类器的权重"""def __init__(self, n_estimators=5):self.n_estimators = n_estimatorsself.estimators = [] # 每个元素是(clf, reverse),reverse表示是否反转预测self.alpha = [] # 弱分类器的权重def fit(self, X, y):"""训练AdaBoost模型参数:X: 特征矩阵(n_samples, n_features)y: 标签(n_samples,),取值为+1(正类,如欺诈)或-1(负类,如正常)"""n_samples = X.shape[0]# 1. 初始化样本权重:每个样本权重相等,总和为1w = np.ones(n_samples) / n_samplesfor t in range(self.n_estimators):# 2. 训练弱分类器(决策树桩,max_depth=1)clf = DecisionTreeClassifier(max_depth=1, random_state=42)clf.fit(X, y, sample_weight=w) # 传入样本权重y_pred = clf.predict(X)# 3. 计算加权错误率(误分类样本的权重之和)error = w.dot(y_pred != y) # 等价于sum(w[i] for i in range(n_samples) if y_pred[i] != y[i])# 确保弱分类器性能优于随机猜测(错误率<0.5),否则反转预测reverse = Falseif error >= 0.5:# 反转标签重新训练(将y替换为-y)clf.fit(X, -y, sample_weight=w)y_pred = -clf.predict(X) # 反转预测结果以匹配原标签error = w.dot(y_pred != y) # 重新计算错误率(此时应<0.5)reverse = True # 标记该分类器需要反转预测# 4. 计算弱分类器的权重(投票权):避免error=0或1导致无穷大error = np.clip(error, 1e-10, 1 - 1e-10) # 限制error范围alpha = 0.5 * np.log((1 - error) / error) # 公式:α_t = 0.5 * ln((1-ε_t)/ε_t)self.alpha.append(alpha)self.estimators.append((clf, reverse)) # 保存分类器及反转标志# 5. 更新样本权重(误分类样本权重升高,正确分类样本权重降低)# 公式:w_{t+1,i} = w_{t,i} * exp(-α_t * y_i * y_pred_i) / Z_t(Z_t为归一化常数)w *= np.exp(-alpha * y * y_pred)w /= w.sum() # 归一化,确保权重总和为1def predict(self, X):"""预测样本类别参数:X: 特征矩阵(n_samples, n_features)返回:y_pred: 预测标签(n_samples,),取值为+1或-1"""final_pred = np.zeros(X.shape[0])for (clf, reverse), alpha in zip(self.estimators, self.alpha):pred = clf.predict(X)if reverse:pred = -pred # 反转预测以匹配原标签(训练时反转过标签)final_pred += alpha * pred # 加权求和(弱分类器投票)return np.sign(final_pred) # 取符号得到最终预测(+1=正类,-1=负类)if __name__ == "__main__":# 1. 模拟信用卡欺诈检测数据(8个正常交易,2个欺诈交易)data = {'交易金额(元)': [800, 1200, 300, 1500, 200, 900, 1100, 400, 500, 200],'交易时间(小时)': [10, 15, 9, 16, 11, 13, 14, 12, 14, 20],'交易地点(是否异地)': [0, 0, 0, 0, 0, 0, 0, 0, 1, 0], # 1=异地,0=本地'账户历史(月)': [24, 18, 36, 12, 60, 48, 30, 54, 36, 1],'y': [-1, -1, -1, -1, -1, -1, -1, -1, +1, +1] # +1=欺诈(正类),-1=正常(负类)}df = pd.DataFrame(data)X = df.drop('y', axis=1).values # 特征矩阵(10行4列)y = df['y'].values # 标签(10行1列)# 2. 训练AdaBoost模型(用3个弱分类器)adaboost = AdaBoost(n_estimators=3)adaboost.fit(X, y)# 3. 预测训练集(评估模型效果)y_pred = adaboost.predict(X)# 4. 输出评估结果print("=== 模型效果评估 ===")print(f"训练集准确率:{accuracy_score(y, y_pred):.2f}")print("混淆矩阵(行=真实标签,列=预测标签;行/列顺序:-1(正常)、+1(欺诈)):")print(confusion_matrix(y, y_pred)) # 混淆矩阵解读:[0,0]=正常样本正确数,[1,1]=欺诈样本正确数# 5. 测试难样本(欺诈样本9和10,索引从0开始)print("\n=== 难样本预测 ===")# 样本9(索引8):交易金额500元、时间14点、异地、账户历史36个月(真实标签+1)sample9 = np.array([[500, 14, 1, 36]])pred9 = adaboost.predict(sample9)[0]print(f"样本9预测结果:{pred9}(正确标签:+1)")# 样本10(索引9):交易金额200元、时间20点、本地、账户历史1个月(真实标签+1)sample10 = np.array([[200, 20, 0, 1]])pred10 = adaboost.predict(sample10)[0]print(f"样本10预测结果:{pred10}(正确标签:+1)")
三、代码使用说明
1.环境准备
需要安装以下库(用pip install命令):
numpy:数值计算;
pandas:数据处理;
scikit-learn:机器学习工具(提供决策树桩)。
2.数据替换
若要使用自己的数据,只需将data字典替换为你的数据(特征字段可调整,标签y需为+1(正类,如欺诈)或-1(负类,如正常))。
3.调整参数
n_estimators:弱分类器数量(默认5)。数量越多,模型越复杂,但可能过拟合。数模中常用50或100,可通过交叉验证选择。
弱分类器:代码中用了DecisionTreeClassifier(max_depth=1)(决策树桩),若要替换为其他弱分类器(如线性分类器),只需修改fit函数中的clf定义(如from sklearn.linear_model import LogisticRegression,然后clf=LogisticRegression() )。
4.运行结果解释
准确率:训练集准确率越高,说明模型对训练数据的拟合越好(但需注意过拟合)。
混淆矩阵:展示模型对正类(欺诈)和负类(正常)的预测情况。例如,混淆矩阵的(0,0)元素表示正常样本被正确预测的数量,(1,1)表示欺诈样本被正确预测的数量;(1,0)表示欺诈样本被误判为正常的数量(需重点关注)。
难样本预测:代码最后测试了两个欺诈样本(样本9和10),若预测结果为+1,说明模型成功识别了这些“难样本”。
四、关键代码逻辑说明
样本权重初始化:w = np.ones(n_samples) / n_samples,每个样本初始权重相等(总和为 1)。
弱分类器训练:使用DecisionTreeClassifier(max_depth=1)(决策树桩),并通过sample_weight=w传入样本权重,让模型重点学习高权重样本(难样本)。
错误率计算:error = w.dot(y_pred != y),计算加权错误率(误分类样本的权重之和)。为避免error=0或1导致无穷大,添加np.clip(error, 1e-10, 1 - 1e-10)限制范围。
权重更新:w *= np.exp(-alpha * y * y_pred),误分类样本的权重会乘以exp(alpha)(升高),正确分类样本的权重乘以exp(-alpha)(降低),然后归一化(w /= w.sum())。
组合预测:final_pred += alpha * pred,将每个弱分类器的预测结果加权求和(alpha 为弱分类器的 “投票权”),最后用np.sign取符号得到最终预测(+1或-1)。
通过本代码,数模小白可以快速理解AdaBoost的核心逻辑,并将其应用于自己的分类问题中。