从零用Python实现粒子群算法优化XGBoost分类模型超参数
时间:2026年06月14日 09:34:09
来源:易频IT社区
一、前期环境准备
1.1 安装依赖库
打开终端(Windows用PowerShell/CMD,Mac/Linux用Terminal),复制粘贴以下命令并回车执行:
```bash
pip install numpy scikit-learn xgboost joblib
```
依赖说明:
- numpy:负责基础数值计算
- scikit-learn:提供数据集、评估指标
- xgboost:待优化的分类模型
- joblib:保存/加载优化后的模型
1.2 验证环境
创建Python文件`verify_env.py`,粘贴以下代码并运行,无报错即成功:
```python
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
import xgboost as xgb
print("依赖库安装成功")
```
二、数据集准备
使用scikit-learn自带的鸢尾花分类数据集,无需额外下载。创建文件`prepare_data.py`,内容如下:
```python
from sklearn import datasets
from sklearn.model_selection import train_test_split
加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data 特征:萼片/花瓣的长宽
y = iris.target 标签:0/1/2代表3种鸢尾花
按8:2划分训练集和测试集,固定随机数种子保证结果可复现
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
stratify=y确保训练/测试集中各类别比例一致
```
三、实现基础粒子群算法(PSO)
PSO的核心逻辑是:每个“粒子”代表一组超参数,粒子群在参数空间里移动,根据“自身历史最优位置”和“全局历史最优位置”调整移动方向。
创建文件`pso_optimizer.py`,完整代码如下:
```python
import numpy as np
import xgboost as xgb
from sklearn.metrics import accuracy_score
from joblib import parallel_backend
class PSOXGBOptimizer:
def __init__(
self,
X_train, y_train, X_test, y_test,
n_particles=20, 粒子数量,建议10-30
max_iter=50, 最大迭代次数,建议30-100
w=0.7, 惯性权重,控制历史速度影响
c1=1.5, 自我认知系数
c2=1.5 社会认知系数
):
数据初始化
self.X_train = X_train
self.y_train = y_train
self.X_test = X_test
self.y_test = y_test
PSO参数初始化
self.n_particles = n_particles
self.max_iter = max_iter
self.w = w
self.c1 = c1
self.c2 = c2
超参数搜索空间:键是参数名,值是(最小值, 最大值, 数据类型)
self.param_bounds = {
"n_estimators": (50, 300, int), 树的数量
"max_depth": (3, 10, int), 树的最大深度
"learning_rate": (0.01, 0.3, float), 学习率
"subsample": (0.5, 1.0, float), 训练每棵树的样本采样比例
"colsample_bytree": (0.5, 1.0, float) 训练每棵树的特征采样比例
}
初始化粒子群位置和速度
self.n_params = len(self.param_bounds)
self.particles = self._init_particles()
self.velocities = np.random.uniform(-1, 1, (self.n_particles, self.n_params))
初始化最优位置和最优分数
self.pbest_positions = self.particles.copy()
self.pbest_scores = np.array([self._evaluate(p) for p in self.particles])
self.gbest_idx = np.argmax(self.pbest_scores)
self.gbest_position = self.pbest_positions[self.gbest_idx].copy()
self.gbest_score = self.pbest_scores[self.gbest_idx]
def _init_particles(self):
"""随机生成粒子群的初始位置(符合搜索空间的数据类型)"""
particles = np.zeros((self.n_particles, self.n_params))
for i, (key, (min_val, max_val, dtype)) in enumerate(self.param_bounds.items()):
if dtype == int:
particles[:, i] = np.random.randint(min_val, max_val+1, self.n_particles)
elif dtype == float:
particles[:, i] = np.random.uniform(min_val, max_val, self.n_particles)
return particles
def _clip_particle(self, particle):
"""将粒子的位置限制在搜索空间内,并转换为对应数据类型"""
clipped = []
for i, (key, (min_val, max_val, dtype)) in enumerate(self.param_bounds.items()):
val = particle[i]
限制范围
val = max(min_val, min(max_val, val))
转换类型
if dtype == int:
val = int(round(val))
clipped.append(val)
return np.array(clipped)
def _evaluate(self, particle):
"""评估单个粒子(一组超参数)的测试集准确率"""
将粒子位置转换为XGBoost参数字典
params = dict(zip(self.param_bounds.keys(), particle))
补充XGBoost分类器的固定参数
params.update({
"objective": "multi:softmax", 多分类目标函数
"num_class": 3, 鸢尾花有3类
"random_state": 42, 固定随机数
"n_jobs": -1 用全部CPU核心训练
})
训练模型
model = xgb.XGBClassifier(params)
model.fit(self.X_train, self.y_train)
预测并计算准确率
y_pred = model.predict(self.X_test)
return accuracy_score(self.y_test, y_pred)
def optimize(self):
"""执行PSO优化流程"""
for iter in range(self.max_iter):
打印当前迭代信息
print(f"Iteration {iter+1}/{self.max_iter}, Current Best Accuracy: {self.gbest_score:.4f}")
更新每个粒子的速度和位置
for i in range(self.n_particles):
计算随机因子
r1 = np.random.random(self.n_params)
r2 = np.random.random(self.n_params)
更新速度
self.velocities[i] = (
self.w self.velocities[i]
+ self.c1 r1 (self.pbest_positions[i] - self.particles[i])
+ self.c2 r2 (self.gbest_position - self.particles[i])
)
更新位置并裁剪
self.particles[i] = self._clip_particle(self.particles[i] + self.velocities[i])
评估新位置
current_score = self._evaluate(self.particles[i])
更新自身最优
if current_score > self.pbest_scores[i]:
self.pbest_positions[i] = self.particles[i].copy()
self.pbest_scores[i] = current_score
更新全局最优
if current_score > self.gbest_score:
self.gbest_position = self.particles[i].copy()
self.gbest_score = current_score
优化结束,返回最优参数和最优分数
best_params = dict(zip(self.param_bounds.keys(), self.gbest_position))
return best_params, self.gbest_score
```
四、执行超参数优化并验证
创建主文件`main.py`,内容如下,可直接运行:
```python
from prepare_data import X_train, X_test, y_train, y_test
from pso_optimizer import PSOXGBOptimizer
import xgboost as xgb
from joblib import dump
1. 初始化PSO优化器
optimizer = PSOXGBOptimizer(
X_train, y_train, X_test, y_test,
n_particles=15,
max_iter=30
)
2. 执行优化
best_params, best_score = optimizer.optimize()
print("\n=== 优化完成 ===")
print(f"最优超参数:{best_params}")
print(f"最优测试集准确率:{best_score:.4f}")
3. 用最优参数重新训练完整模型(可选)
full_model = xgb.XGBClassifier(
best_params,
objective="multi:softmax",
num_class=3,
random_state=42,
n_jobs=-1
)
full_model.fit(X_train, y_train)
4. 保存模型
dump(full_model, "optimized_xgb_iris.joblib")
print("优化后的模型已保存为 optimized_xgb_iris.joblib")
```
五、常见问题排查
1. 依赖安装失败:如果使用pip安装报错,可尝试使用国内镜像源,替换命令为:
```bash
pip install numpy scikit-learn xgboost joblib -i https://pypi.tuna.tsinghua.edu.cn/simple
```
2. 准确率波动大:检查是否在`train_test_split`、PSO类初始化、XGBoost初始化中都设置了`random_state=42`
3. 优化速度慢:适当减少`n_particles`或`max_iter`,或确保`n_jobs=-1`已生效
六、扩展提示
如果需要优化其他模型(如LightGBM、SVM),只需修改`_evaluate`方法中的模型类和固定参数;如果需要调整超参数搜索空间,只需修改`param_bounds`字典的内容。