前言
本文章将建立三层结构的机器学习模型,第一层传统机器学习算法,第二层集成学习,第三层门控专家模型。这套模型用于非时序数据回归任务的预测,比如房价预测、二手车价格预测等。
一、个体传统机器学习算法
算法选择
最基础的个体学习器使用以下模型:
CatBoost
Lasso (Lasso Regression)
LightGBM (Light Gradient Boosting Machine)
ElasticNet
XGBoost
Ridge (Ridge Regression)
实际上还可以加上SVR和GBR,但他们面对十万级的数据实在太慢,12个小时都训练不出来。
个体学习器训练代码
cat_model = cat_boost_model.fit(X_train,y_train)
lasso_model = lasso_model_full_data.fit(X_train,y_train)
lgbm_model = lgb_model_full_data.fit(X_train,y_train)
elastic_model = elastic_model_full_data.fit(X_train,y_train)
xgboost_model = xgboost.fit(X_train,y_train)
ridge_model = ridge.fit(X_train,y_train)
个体学习器优化
实际上最好的优化方法就是在第三层次上所有参数一起进行优化,但是时间效率根本上不可能,哪怕是在第二层次上进行优化,在时间和效率上都是无法忍受的。
学习器优化代码参考
def optimize_lasso(loss):
def objective(trial):
# 优化归一化方法
scaler_name = trial.suggest_categorical('scaler', ['StandardScaler', 'MinMaxScaler', 'RobustScaler'])
if scaler_name == 'StandardScaler':
scaler = StandardScaler()
elif scaler_name == 'MinMaxScaler':
scaler = MinMaxScaler()
else:
scaler = RobustScaler()
# 优化Ridge模型的参数
alpha = trial.suggest_float('alpha', 1e-3, 10.0, log=True) # alpha的范围
tol = trial.suggest_float('tol', 1e-5, 1e-2, log=True)
selection = trial.suggest_categorical('selection', ['cyclic', 'random'])
# 定义管道
lasso_pipeline = make_pipeline(scaler, Lasso(alpha=alpha, tol=tol, selection=selection, random_state=42))
# 进行交叉验证,并返回得分的平均值
score = loss(lasso_pipeline)
return score.mean() # 返回平均负均方误差
# 创建研究对象
study = optuna.create_study(direction='minimize')
# 优化目标函数
study.optimize(objective, n_trials=50)
# 输出最优参数和最小的均方误差
print('Best trial:')
trial = study.best_trial
print(f' Value: {trial.value}')
print(' Params:')
for key, value in trial.params.items():
print(f' {key}: {value}')
optimize_lasso(cv_rmse)
二、集成学习
模型定义
值得注意的是,并非使用所有个体学习器效果就会更好,使用不同的元学习器效果也会不同,同时元学习器不一定要用在基学习器中,这是可以用来寻优的。基学习器和元学习器可以有不同组合。
stack_gen = StackingCVRegressor(regressors=(elastic_model_full_data, xgboost,lgb_model_full_data),
meta_regressor=xgboost,
use_features_in_secondary=True)
三、门控专家模型
模型使用
专家模型使用以下模型,即第一层和第二层的模型
CatBoost
StackingCVRegressor
Lasso (Lasso Regression)
LightGBM (Light Gradient Boosting Machine)
ElasticNet
XGBoost
Ridge (Ridge Regression)
门控网络使用简单的MLP,他用来动态控制各个专家模型的权重,面对不同数据的时候使用不同的权重。MLP也可以进行参数优化。
整体情况如下
训练
for epoch in range(epoch_num):
model.train() # 设置为训练模式
result = torch.zeros_like(y_train_tensor) # 初始化结果张量
# 前向传播
output = model(X_train_tensor)
for i in range(output_size):
result += output[:, i]*expert_train[i]
# 计算损失
loss = criterion(result, y_train_tensor)
train_losses.append(loss.item()) # 收集训练损失
print('train_loss:',loss.item())
# # 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 验证
model.eval() # 设置为评估模式,关闭 dropout 等
with torch.no_grad():
result_val = torch.zeros_like(y_test_tensor) # 初始化验证结果张量
output_val = model(X_test_tensor)
for i in range(output_size):
result_val += output_val[:, i] * expert_val[i]
val_loss = criterion(result_val, y_test_tensor)
val_losses.append(val_loss.item()) # 收集验证损失
print(f'Epoch {epoch+1}/{epoch_num}, val_loss: {val_loss.item()}')
# 如果验证损失较低,保存模型
if val_loss.item() < best_val_loss:
best_val_loss = val_loss.item()
torch.save(model.state_dict(), best_model_path)
print(f'Saved best model with val_loss: {best_val_loss}')
总结
实际上,整个过程中的MLP和个体学习器的训练是有一定问题的,如果将数据分为1比9,1作为验证集,9作为训练集,使用该训练集对个体学习器进行训练,但在MLP的训练时,个体学习器却需要对原来的训练集进行预测,这会造成数据泄露。
也许将训练集再次划分会更好。