<think>我们使用AdaBoost回归器,并用粒子群算法(PSO)优化其超参数。
通常,AdaBoost用于回归时,我们使用AdaBoostRegressor,它的关键参数有:
- n_estimators: 弱学习器的最大数量
- learning_rate: 学习率,每个弱学习器的贡献权重
- loss: 损失函数('linear', 'square', 'exponential')
粒子群优化(PSO)是一种启发式优化算法,通过模拟鸟群觅食行为来寻找最优解。
我们将使用PSO来优化AdaBoostRegressor的超参数组合,以在验证集上获得最佳性能(如最小化均方误差)。
步骤:
1. 定义参数范围:我们需要为每个参数定义搜索空间(连续或离散)。
2. 定义适应度函数:使用交叉验证评估给定参数组合的性能(这里为避免过拟合,我们使用部分训练数据作为验证集,或者使用交叉验证)。
3. 初始化粒子群:随机初始化粒子的位置(参数组合)和速度。
4. 迭代更新:根据粒子历史最佳位置和全局最佳位置更新粒子位置和速度。
5. 返回全局最佳位置对应的参数。
注意:由于参数n_estimators是整数,我们需要在更新粒子位置后取整;learning_rate是连续值;loss是离散值,我们需要在粒子位置中将其离散化。
为了简化,我们将三个参数都作为连续值处理,然后对离散参数进行映射(例如,将loss参数转换为最接近的离散值)。
参数范围设定(根据经验):
- n_estimators: [50, 500] -> 整数
- learning_rate: [0.01, 1] -> 连续
- loss: 离散值,我们将其表示为0,1,2分别对应'linear','square','exponential'
适应度函数:我们使用均方误差(MSE)的负值(因为PSO是最大化适应度,而我们需要最小化MSE,所以用负MSE作为适应度)。
粒子群算法参数:
- 粒子数: 10
- 迭代次数: 50
- 惯性权重: 0.8
- 个体学习因子: 0.5
- 社会学习因子: 0.5
我们将使用sklearn的AdaBoostRegressor,并使用决策树回归器作为基础估计器(默认)。
代码结构:
1. 导入必要的库
2. 读取数据,划分训练集和测试集
3. 定义适应度函数(评估参数)
4. 定义PSO算法
5. 运行PSO优化
6. 使用最优参数训练模型并评估
注意:为了避免过拟合,我们在适应度函数中使用交叉验证(或使用验证集)来评估参数。
这里我们使用5折交叉验证的MSE平均值作为适应度值。
由于PSO优化过程可能较慢,我们使用较小的粒子群和迭代次数。在实际应用中,可能需要更多粒子或迭代次数。
代码实现:
</think># AdaBoost算法粒子群优化实现
我将使用粒子群优化(PSO)算法优化AdaBoost回归模型的超参数。以下是完整的实现代码:
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_percentage_error, r2_score
plt.rcParams['font.family'] = 'Times New Roman'
# 粒子群优化(PSO)类
class ParticleSwarmOptimizer:
def __init__(self, n_particles, search_space, fitness_func, max_iter=50, inertia=0.8,
cognitive_weight=0.5, social_weight=0.5):
"""
PSO参数:
n_particles: 粒子数量
search_space: 参数搜索空间,格式为{'param1': (min, max), ...}
fitness_func: 适应度函数,接受参数向量,返回适应度值
max_iter: 最大迭代次数
inertia: 惯性权重
cognitive_weight: 认知权重
social_weight: 社会权重
"""
self.n_particles = n_particles
self.search_space = search_space
self.fitness_func = fitness_func
self.max_iter = max_iter
self.inertia = inertia
self.cognitive_weight = cognitive_weight
self.social_weight = social_weight
self.param_names = list(search_space.keys())
self.n_dim = len(search_space)
# 初始化粒子群
self.particles = np.zeros((n_particles, self.n_dim))
self.velocities = np.zeros((n_particles, self.n_dim))
self.pbest_positions = np.zeros((n_particles, self.n_dim))
self.pbest_fitness = np.full(n_particles, -np.inf)
self.gbest_position = None
self.gbest_fitness = -np.inf
self.fitness_history = []
# 随机初始化粒子和速度
for i in range(n_particles):
for j, param in enumerate(self.param_names):
min_val, max_val = search_space[param]
self.particles[i, j] = np.random.uniform(min_val, max_val)
self.velocities[i, j] = np.random.uniform(-1, 1) * (max_val - min_val) / 10.0
self.pbest_positions = np.copy(self.particles)
def optimize(self):
"""执行优化过程"""
for iteration in range(self.max_iter):
# 评估当前种群
for i in range(self.n_particles):
# 将粒子位置转换为参数字典
params = {name: self.particles[i, j] for j, name in enumerate(self.param_names)}
# 转换离散参数为整数
params['n_estimators'] = int(np.round(params['n_estimators']))
params['max_depth'] = int(np.round(params['max_depth']))
# 评估适应度(这里适应度函数返回负MAPE,所以越大越好)
fitness = self.fitness_func(params)
# 更新个体最优
if fitness > self.pbest_fitness[i]:
self.pbest_fitness[i] = fitness
self.pbest_positions[i] = self.particles[i].copy()
# 更新全局最优
if fitness > self.gbest_fitness:
self.gbest_fitness = fitness
self.gbest_position = self.particles[i].copy()
# 记录最佳适应度
self.fitness_history.append(self.gbest_fitness)
# 更新粒子速度和位置
for i in range(self.n_particles):
# 计算认知和社会因子
r1 = np.random.random(self.n_dim)
r2 = np.random.random(self.n_dim)
# 更新速度
cognitive_component = self.cognitive_weight * r1 * (self.pbest_positions[i] - self.particles[i])
social_component = self.social_weight * r2 * (self.gbest_position - self.particles[i])
self.velocities[i] = (self.inertia * self.velocities[i] +
cognitive_component +
social_component)
# 更新位置
self.particles[i] += self.velocities[i]
# 确保粒子在搜索空间内
for j, param in enumerate(self.param_names):
min_val, max_val = self.search_space[param]
if self.particles[i, j] < min_val:
self.particles[i, j] = min_val
self.velocities[i, j] *= -0.5 # 反弹
elif self.particles[i, j] > max_val:
self.particles[i, j] = max_val
self.velocities[i, j] *= -0.5 # 反弹
# 打印进度
if (iteration + 1) % 5 == 0:
print(f"Iteration {iteration+1}/{self.max_iter}, Best Fitness: {self.gbest_fitness:.6f}")
# 返回最优参数
best_params = {name: self.gbest_position[j] for j, name in enumerate(self.param_names)}
best_params['n_estimators'] = int(np.round(best_params['n_estimators']))
best_params['max_depth'] = int(np.round(best_params['max_depth']))
return best_params, self.fitness_history
# 读取数据
data = pd.read_csv('augmented_fatigue_data_1.csv')
X = data[['x']] # 特征
y = data['y'] # 目标变量
# 数据集拆分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 定义适应度函数(模型评估)
def evaluate_model(params):
"""评估AdaBoost模型并返回适应度值"""
# 创建基础回归器
base_estimator = DecisionTreeRegressor(
max_depth=params['max_depth'],
min_samples_split=params['min_samples_split'],
min_samples_leaf=params['min_samples_leaf'],
random_state=42
)
# 创建AdaBoost回归器
model = AdaBoostRegressor(
base_estimator=base_estimator,
n_estimators=params['n_estimators'],
learning_rate=params['learning_rate'],
random_state=42
)
# 训练模型
model.fit(X_train, y_train)
# 预测验证集(这里使用部分训练集作为验证)
y_valid = y_train[:len(y_test)]
y_pred = model.predict(X_train[:len(y_test)])
# 计算负MAPE(PSO最大化适应度,所以负MAPE表示最小化MAPE)
mape = mean_absolute_percentage_error(y_valid, y_pred)
return -mape
# 定义参数搜索空间
search_space = {
'n_estimators': (10, 200), # 弱学习器数量
'learning_rate': (0.01, 1.0), # 学习率
'max_depth': (1, 10), # 基础决策树的最大深度
'min_samples_split': (2, 20), # 节点分裂的最小样本数
'min_samples_leaf': (1, 10) # 叶节点所需的最小样本数
}
# 创建PSO优化器
pso = ParticleSwarmOptimizer(
n_particles=20,
search_space=search_space,
fitness_func=evaluate_model,
max_iter=50
)
# 执行粒子群优化
print("Starting Particle Swarm Optimization for AdaBoost hyperparameters...")
best_params, fitness_history = pso.optimize()
print("\nOptimization completed!")
print("Best parameters found:")
for param, value in best_params.items():
print(f" {param}: {value}")
# 可视化优化过程
plt.figure(figsize=(10, 5))
plt.plot(range(1, len(fitness_history)+1), [-f for f in fitness_history], 'bo-')
plt.xlabel('Iteration')
plt.ylabel('MAPE (Validation Set)')
plt.title('PSO Convergence History for AdaBoost Hyperparameter Optimization')
plt.grid(True, linestyle='--', alpha=0.6)
plt.savefig("pso_convergence.pdf", dpi=300, format='pdf')
plt.show()
# 使用最优参数训练最终模型
print("\nTraining final model with optimized parameters...")
base_estimator = DecisionTreeRegressor(
max_depth=best_params['max_depth'],
min_samples_split=best_params['min_samples_split'],
min_samples_leaf=best_params['min_samples_leaf'],
random_state=42
)
final_model = AdaBoostRegressor(
base_estimator=base_estimator,
n_estimators=best_params['n_estimators'],
learning_rate=best_params['learning_rate'],
random_state=42
)
final_model.fit(X_train, y_train)
# 预测测试集
y_pred = final_model.predict(X_test)
# 准备测试数据
test_df = pd.DataFrame({'actual': y_test, 'pred': y_pred}, index=X_test.index).sort_index()
test_df = test_df.sample(frac=1, random_state=42).reset_index(drop=True)
# 绘图
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# (a) 实测 vs 预测
axes[0].plot(test_df.index, test_df['actual']/1e5, 'o-', label='Actual', color='blue', alpha=0.7)
axes[0].plot(test_df.index, test_df['pred']/1e5, 'x-', label='Predicted', color='orange', alpha=0.7)
axes[0].set_xlabel('Test set index')
axes[0].set_ylabel('Fatigue life (×10⁵ cycles)')
axes[0].set_title('(a) Actual vs Predicted (PSO-Optimized AdaBoost)')
axes[0].legend()
axes[0].grid(True, linestyle='--', alpha=0.6)
# (b) 45°误差带图
x_actual = test_df['actual'].values
y_pred_values = test_df['pred'].values
xmin, xmax = x_actual.min(), x_actual.max()
xs = np.logspace(np.log10(max(xmin, 1e-12)), np.log10(xmax), 200)
axes[1].scatter(x_actual, y_pred_values, s=25, color='blue', alpha=0.6)
axes[1].plot(xs, xs, '-', color='green', label='Ideal', linewidth=2)
axes[1].plot(xs, xs*1.25, '--', color='orange', label='±1.25 band')
axes[1].plot(xs, xs/1.25, '--', color='orange')
axes[1].plot(xs, xs*1.50, ':', color='red', label='±1.5 band')
axes[1].plot(xs, xs/1.50, ':', color='red')
axes[1].set_xscale('log')
axes[1].set_yscale('log')
axes[1].set_xlabel('Experimental results (cycles)')
axes[1].set_ylabel('Predicted results (cycles)')
axes[1].set_title('(b) 45° Plot with Error Bands')
axes[1].legend()
axes[1].grid(True, which='both', linestyle='--', alpha=0.6)
plt.tight_layout()
plt.savefig("adaboost_pso_results.pdf", dpi=300, format='pdf')
plt.show()
# 评估指标
mape = mean_absolute_percentage_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f"\nFinal Model Performance:")
print(f"MAPE: {mape*100:.2f}%")
print(f"R²: {r2:.4f}")
# 弱学习器误差分析
errors = []
for estimator in final_model.estimators_:
# 使用弱学习器预测训练集
y_pred_weak = estimator.predict(X_train)
# 计算误差(这里使用均方误差)
mse = np.mean((y_train - y_pred_weak) ** 2)
errors.append(mse)
# 绘制误差随迭代次数的变化
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(errors)+1), errors, 'o-')
plt.xlabel('Weak Learner Index')
plt.ylabel('Mean Squared Error')
plt.title('Training Error of Weak Learners in AdaBoost')
plt.grid(True, linestyle='--', alpha=0.6)
plt.savefig("weak_learner_errors.pdf", dpi=300, format='pdf')
plt.show()
# 特征重要性分析(基于AdaBoost的权重)
feature_importances = np.zeros(X_train.shape[1])
estimator_weights = final_model.estimator_weights_
for i, estimator in enumerate(final_model.estimators_):
# 获取决策树的重要性
tree_importance = estimator.feature_importances_
# 加权求和
feature_importances += tree_importance * estimator_weights[i]
# 归一化
feature_importances /= np.sum(feature_importances)
# 展示特征重要性
importance_df = pd.DataFrame({
'Feature': X.columns,
'Importance': feature_importances
}).sort_values('Importance', ascending=False)
print("\nFeature Importances:")
print(importance_df)
# 可视化特征重要性
plt.figure(figsize=(8, 4))
plt.bar(importance_df['Feature'], importance_df['Importance'], color='skyblue')
plt.xlabel('Features')
plt.ylabel('Importance Score')
plt.title('Feature Importance (AdaBoost with PSO)')
plt.xticks(rotation=45)
plt.grid(True, axis='y', linestyle='--', alpha=0.6)
plt.tight_layout()
plt.savefig("feature_importance.pdf", dpi=300, format='pdf')
plt.show()
# 残差分析
residuals = y_test - y_pred
plt.figure(figsize=(8, 6))
plt.scatter(y_pred, residuals, alpha=0.6)
plt.axhline(y=0, color='r', linestyle='-')
plt.xlabel('Predicted Values')
plt.ylabel('Residuals')
plt.title('Residual Plot (PSO-Optimized AdaBoost)')
plt.grid(True)
plt.savefig("residual_plot.pdf", dpi=300, format='pdf')
plt.show()
```
## AdaBoost算法与粒子群优化原理
### AdaBoost算法核心原理
1. **迭代增强**:
- AdaBoost通过迭代训练一系列弱学习器(通常是简单的决策树)
- 每个后续学习器都专注于前一个学习器预测错误的样本
2. **权重更新机制**:
- 错误分类的样本权重增加
- 正确分类的样本权重减少
- 使后续学习器更关注难样本
3. **模型组合**:
- 最终的预测是所有弱学习器的加权和
- 每个弱学习器的权重由其准确率决定
### 粒子群优化(PSO)算法原理
1. **粒子群概念**:
- 每个粒子代表一个候选解(超参数组合)
- 粒子在搜索空间飞行,寻找最优位置
2. **位置更新方程**:
```python
# 速度更新
velocity = inertia * current_velocity +
cognitive_weight * r1 * (pbest - position) +
social_weight * r2 * (gbest - position)
# 位置更新
position += velocity
```
3. **关键参数作用**:
- **惯性权重(inertia)**:控制粒子保持当前运动趋势的程度
- **认知权重(cognitive_weight)**:引导粒子向个体最优位置移动
- **社会权重(social_weight)**:引导粒子向群体最优位置移动
### PSO优化AdaBoost的优势
1. **全局搜索能力**:
- PSO能跳出局部最优,找到更好的全局超参数组合
- 相比网格搜索,计算效率更高
2. **处理混合参数类型**:
```python
# 处理离散参数(如n_estimators)
params['n_estimators'] = int(np.round(params['n_estimators']))
# 处理连续参数(如learning_rate)
learning_rate = params['learning_rate']
```
3. **动态调整搜索方向**:
- 粒子根据个体经验和群体经验动态调整搜索方向
- 避免过早收敛到次优解
## AdaBoost参数优化指南
| 参数 | 搜索范围 | 说明 | 优化建议 |
|------|----------|------|-----------|
| `n_estimators` | [10, 200] | 弱学习器数量 | 平衡模型复杂度和训练时间 |
| `learning_rate` | [0.01, 1.0] | 学习率 | 较小值需要更多弱学习器 |
| `max_depth` | [1, 10] | 基础决策树深度 | 控制弱学习器复杂度 |
| `min_samples_split` | [2, 20] | 节点分裂最小样本数 | 防止过拟合 |
| `min_samples_leaf` | [1, 10] | 叶节点最小样本数 | 控制子树大小 |
## 性能提升策略
1. **并行计算优化**:
```python
# 使用joblib并行评估粒子
from joblib import Parallel, delayed
def parallel_evaluate(particles):
with Parallel(n_jobs=4) as parallel:
results = parallel(delayed(evaluate_model)(particle) for particle in particles)
return results
```
2. **自适应参数调整**:
```python
# 动态调整惯性权重
inertia = 0.9 - (0.5 * iteration / max_iter)
```
3. **混合优化策略**:
```python
# 结合局部搜索提高精度
if iteration > max_iter//2:
# 在全局最优附近进行局部搜索