发动机剩余使用寿命预测(4)

职场   2025-01-03 17:16   四川  
在上一篇总结中我们使用XGBoost算法预测了发动机的剩余使用寿命,结果差强人意。今天,我们继续学习一种新的算法:随机森林(Random Forest)。
和XGBoost一样,随机森林也是一种集成学习算法。由多个决策树组成,通过多个弱学习器形成一个强学习器。决策树是随机森林的基本组成单元,每棵决策树通过一系列的if-then规则将特征空间划分为不同的区域,每个区域对应一个输出值随机森林通过构建多个这样的决策树,并将它们的结果进行汇总,来得到最终的预测结果。在回归任务中,最终预测值为所有决策树的预测值的平均值:
它与XGBoost算法有什么区别呢?
特性
随机森林 (RF)
XGBoost
集成方法
Bagging(Bootstrap  Aggregating)
Boosting(梯度提升法)
基学习器
多棵独立的决策树(并行训练)
多棵串联的决策树(逐步构建,每棵树依赖前一棵)
训练方式
每棵树独立训练,相互之间无依赖关系
按顺序训练,每棵树学习前面树的误差
模型更新方式
无需调整历史树,直接用平均值做最终预测
新树逐步修正前面树的预测误差
损失函数优化
最小化均方误差(MSE)
使用梯度下降优化损失函数
处理偏差与方差的方式
降低方差为主,通过随机性避免过拟合
降低偏差为主,通过梯度更新减少训练误差

从上述对比不难看出,RF比较适合数据量较小、数据特征较简单的任务。如果需求是快速建模和基础预测分析,可以优先考虑随机森林。

怎么理解Bagging(Bootstrap Aggregating,自助采样)呢?它的核心思想其实就是通过对数据进行随机采样和重复训练多个弱学习器,最终将多个预测结果组合来获得更稳健的预测结果。简单的说就是:多次抽样 + 多模型训练 + 结果集成
它其实是一种统计方法:假设我们有一个班级所有学生的考试成绩,而我们要估计所有学生的平均分。于是我们随机抽取了5名学生的分数作为样本:[85、90、75、98、56]。
有放回抽样(Bootstrap)就是每次抽取一组样本后,将其再放回原始样本中,然后再次抽取。这样,我们可以生成多个新的样本集合,每个集合都包含5个分数数据,当然这些数据可能包含重复的值。例如:
第一次抽样得到:[85、90、75、98、56]
第二次抽样得到:[100、78、95、67、89]
以此类推,如果我们进行100次抽样,就能得到100个新的样本集合。对于每个样本集合,我们计算均值:
第一个样本集合的平均值是:(85+90+75+98+56)/5=80.8
第二个样本集合的平均值是:(100+78+95+67+89)/5=85.8
然后取这100个均值的平均值来作为全班平均分数的估计。讲到这里,不知道有没有人会有这样一个疑问:既然已经知道所有学生的成绩了,为啥不直接算平均,还要用有放回抽样来估算呢? 
因为在现实生活中,我们手上的总体数据往往是非常大的,处理起来非常困难!有时我们无法获得整个总体数据。这时,随机采样就会显得非常有用!上面举的例子只是为了便于大家理解。

RandomForestRegressor 是scikit-learn中实现随机森林回归的强大工具,它是一种特化版的 Bagging 回归模型,除了对样本进行有放回抽样,每棵树的训练还会随机选择部分特征用于分裂,而且每棵树通常会生长到最大深度。这样增加了模型的多样性,降低了过拟合的风险。
模型的构建和训练非常简单,首先用RandomForestRegressor创建一个随机森林回归模型,再用fit方法来训练模型即可。我们稍微优化一下,和上一篇的XGBoost类似,先设置一个超参数空间并随机生成 50 组参数组合,再在每组参数上执行交叉验证训练和评估模型,计算均方误差(MSE)。然后从随机搜索过程中找到一个最佳参数组合,重新训练模型以获得最佳的泛化能力(前面的代码是一样的啊,下面只展示模型训练部分代码)
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import KFold
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from tqdm import tqdm

# 定义超参数分布
param_distributions = {
    'n_estimators': [100, 200, 300, 400, 500],
    'max_depth': [None, 10, 20, 30, 40, 50],
    'min_samples_split': [2, 5, 10],
    'min_samples_leaf': [1, 2, 4],
    'max_features': ['sqrt''log2'],
    'bootstrap': [True, False]
}

# 初始化随机森林回归模型
model = RandomForestRegressor(random_state=42)

param_list = []
for _ in range(50):  # 随机采样 50 组参数组合
    param_list.append({
        'n_estimators': random.choice(param_distributions['n_estimators']),
        'max_depth': random.choice(param_distributions['max_depth']),
        'min_samples_split': random.choice(param_distributions['min_samples_split']),
        'min_samples_leaf': random.choice(param_distributions['min_samples_leaf']),
        'max_features': random.choice(param_distributions['max_features']),
        'bootstrap': random.choice(param_distributions['bootstrap'])
    })
    
# 设置交叉验证
cv_splitter = KFold(n_splits=3, shuffle=True, random_state=42)

# 遍历所有参数组合
results = []
with tqdm(total=len(param_list), desc="Random Search Progress") as pbar:
    for params in param_list:  
        model.set_params(**params)  # 更新模型参数
        scores = []
        for train_idx, val_idx in cv_splitter.split(flat_seq_array, label_array.ravel()):
            # 在训练集上训练模型
            model.fit(flat_seq_array[train_idx], label_array.ravel()[train_idx])
            # 在验证集上预测并计算误差
            preds = model.predict(flat_seq_array[val_idx])
            score = mean_squared_error(label_array.ravel()[val_idx], preds)
            scores.append(score)
        avg_score = np.mean(scores)  # 计算平均误差
        results.append({'params': params, 'mean_test_score': avg_score})  # 记录结果
        pbar.update(1)  # 更新进度条
        
# 获取最佳参数和结果
best_result = min(results, key=lambda x: x['mean_test_score'])  # 找到误差最小的结果
best_params = best_result['params']  # 最优超参数
best_score = best_result['mean_test_score']  # 最优得分
# 输出最佳参数和分数
print(f"最佳参数: {best_params}")
print(f"最佳得分 (MSE): {best_score}")

# 使用最佳参数重新训练模型
best_rf_model = RandomForestRegressor(**best_params, random_state=42)  # 根据最佳参数初始化模型
best_rf_model.fit(flat_seq_array, label_array.ravel())  # 在全部训练数据上重新训练模型

# 预测
preds = best_rf_model.predict(flat_test_seq_array)

# 评估模型
mae = mean_absolute_error(test_label_array, preds)
mse = mean_squared_error(test_label_array, preds)
r2 = r2_score(test_label_array, preds)
print(f"Optimized MAE: {mae}, Optimized MSE: {mse}, Optimized R^2: {r2}")
受电脑性能限制,我这里采取的是手动随机搜索。如果你的电脑性能好一些,也可以用RandomizedSearchCV库快速找到相对较好的参数组合(设置内置参数n_jobs=-1,利用多核CPU加快训练速度)。
# 定义随机搜索对象
random_search = RandomizedSearchCV(
    estimator=RandomForestRegressor(random_state=42),
    param_distributions=param_distributions,
    n_iter=50,  # 搜索次数
    scoring='neg_mean_squared_error',  # 评估指标
    cv=3,  # 3折交叉验证
    random_state=42,
    n_jobs=-1  # 并行计算
)
两种方法各有优缺点,手动随机搜索灵活性高,但没法并行计算,在大规模参数搜索时效率低。而RandomizedSearchCV虽然难以对训练过程做细粒度控制,但有交叉验证内置支持,几行代码就能完成超参数搜索,计算效率更高。

最终的预测效果比XGBoost还略差一些,都没有LSTM模型预测得准确。本来还想再尝试用一下另一种集成学习的方法:LightGBM,再写一期,现在看来是没有必要了。对于这种时间依赖性强、样本序列较长的多变量时序数据,深度学习模型比传统的机器学习模型(如 XGBoostLightGBMRandomForest)要更合适一些。



感谢大家对机务论坛的支持,关注机务论坛,倾听机务心声!航企优秀的方面必定宣传,不足的地方也必须指出,让领导们重视问题,解决问题,营造更好的机务维修环境。

征稿:
所见所闻,个人感悟,个人成长历程及感人故事。
特别征稿:我师傅的故事!
同时,征集劳动仲裁案例,分享案例,让更多的小伙伴能了解劳动纠纷的解决方式,通过劳动仲裁维护自己的合法权益。



评论区留言,同意的点赞
扫码添加小编微信
匿名爆料


民航机务论坛微信公众平台
改名为:机务论坛
发布最新行业动向 深入解读政策法规
开辟维修工程专栏 交流飞机排故经验
分享前沿技术应用 预测职业发展前景
行业大咖讲经布道 业界专家授业解惑
致力打造一流的民航机务朋友圈----机务论坛
关注机务论坛,倾听机务心声!
投稿邮箱:duanwei0615@163.com

机务论坛
民航机务论坛改名为:机务论坛 发布最新行业动向 深入解读政策法规 开辟维修工程专栏 交流飞机排故经验 分享前沿技术应用 预测职业发展前景 行业大咖讲经布道 业界专家授业解惑 致力打造一流的民航机务朋友圈----机务论坛
 最新文章