import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error from scipy.optimize import minimize import matplotlib.pyplot as plt from pathlib import Path ------------------ 数据预处理 ------------------ 设置文件路径 excel_path = Path(“C:/Users/Administrator/Desktop/augmented_data3.xlsx”) 读取数据 data = pd.read_excel(excel_path, sheet_name=‘Sheet1’) 特征工程处理 检查并转换分类变量(仅对真正需要编码的列进行处理) cat_cols = [] le = LabelEncoder() 假设’燃尽风位置’是分类变量,进行编码 if data[‘燃尽风位置’].dtype == ‘object’: data[‘燃尽风位置’] = le.fit_transform(data[‘燃尽风位置’]) cat_cols.append(‘燃尽风位置’) 确保温度保持为连续数值(移除之前的字符串转换) X = data[[‘掺氨比’, ‘过量空气系数’, ‘燃尽风位置’, ‘主燃区温度’]] y = data[‘NO排放浓度’]# 在现有数据预处理阶段后添加以下代码(划分训练测试集之前) ------------------ 模型训练 ------------------ 划分训练测试集 X_train_clean, X_test, y_train_clean, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) 随机森林模型配置 rf = RandomForestRegressor( n_estimators=300, max_depth=10, min_samples_split=5, random_state=42 ) 训练模型 rf.fit(X_train_clean, y_train_clean) y_pred = rf.predict(X_test) 计算评估指标 mse = mean_squared_error(y_test, y_pred) rmse = np.sqrt(mse) mae = mean_absolute_error(y_test, y_pred) r_squared = r2_score(y_test, y_pred) print(f’均方误差 (MSE): {mse:.2f}‘) print(f’均方根误差 (RMSE): {rmse:.2f}’) print(f’平均绝对误差 (MAE): {mae:.2f}‘) print(f’决定系数 (R²): {r_squared:.2f}’)# 可视化特征重要性(排序后) plt.rcParams[‘font.sans-serif’] = [‘SimHei’] plt.rcParams[‘axes.unicode_minus’] = False importances = rf.feature_importances_ sorted_idx = importances.argsort() plt.figure(figsize=(10,6)) plt.barh(X.columns[sorted_idx], importances[sorted_idx]) plt.title(“随机森林特征重要性排序”) plt.show() param_bounds = { ‘掺氨比’: (data[‘掺氨比’].min(), data[‘掺氨比’].max()), ‘过量空气系数’: (data[‘过量空气系数’].min(), data[‘过量空气系数’].max()), ‘燃尽风位置’: (data[‘燃尽风位置’].min(), data[‘燃尽风位置’].max()), ‘主燃区温度’: (data[‘主燃区温度’].min(), data[‘主燃区温度’].max()) } def objective(x): # x为待优化参数:[掺氨比, 过量空气系数, 燃尽风位置, 主燃区温度] return rf.predict([x])[0] # 使用训练好的随机森林进行预测 initial_guess = [ data[‘掺氨比’].mean(), data[‘过量空气系数’].mean(), data[‘燃尽风位置’].mean(), data[‘主燃区温度’].mean() ] 定义参数边界(需转换为scipy优化格式) bounds = [ param_bounds[‘掺氨比’], param_bounds[‘过量空气系数’], param_bounds[‘燃尽风位置’], param_bounds[‘主燃区温度’] ] result = minimize( fun=objective, x0=initial_guess, bounds=bounds, method=‘L-BFGS-B’ # 适合有界优化问题 ) if result.success: optimal_params = result.x min_no_emission = result.fun print(f"最低NO排放浓度: {min_no_emission:.2f} mg/m³") print(“最优参数组合:”) print(f"掺氨比: {optimal_params[0]:.3f}“) print(f"过量空气系数: {optimal_params[1]:.3f}”) print(f"燃尽风位置: {optimal_params[2]:.1f}“) print(f"主燃区温度: {optimal_params[3]:.1f} ℃”) else: print(“优化失败,请检查约束条件或算法参数”) 改为使用LightGBM分位数回归+异常值过滤
时间: 2025-06-10 09:07:43 浏览: 17
<think>嗯,用户给了一段Python代码,主要是用随机森林回归模型来预测NO排放浓度,并进行了优化寻找最低排放的参数。现在用户想改为使用LightGBM分位数回归,并且加上异常值过滤。我需要先理解现有的代码流程,然后确定如何修改。
首先,现有的数据预处理部分包括读取Excel数据,对分类变量“燃尽风位置”进行标签编码,划分训练测试集,然后用随机森林训练模型,评估指标,可视化特征重要性,最后用scipy进行优化寻找最小NO排放。
用户的需求是改用LightGBM的分位数回归,同时加入异常值处理。分位数回归通常用于估计条件分位数,比如中位数,这样对异常值可能更鲁棒。不过用户可能想要的是利用分位数回归来处理异常值,或者预测不同分位数的结果,需要明确。
另外,异常值过滤的方法有很多,比如Z-score、IQR等方法,或者使用模型本身检测异常值。但用户可能希望在数据预处理阶段去除异常值,提高模型鲁棒性。
接下来,我需要考虑如何将随机森林替换为LightGBM的分位数回归模型。LightGBM支持分位数回归,通过设置objective='quantile'和alpha参数来指定分位数,比如alpha=0.5对应中位数回归。这可能有助于减少异常值的影响,因为中位数相比平均值对异常值不敏感。
同时,异常值过滤应该在数据预处理阶段进行,可能在划分训练测试集之前。例如,使用IQR方法检测y值(NO排放浓度)中的异常值,然后剔除这些样本。或者使用模型预测的残差来检测异常值,但这样可能需要先训练一个模型,可能会引入循环依赖的问题,所以直接在数据预处理时处理更合适。
然后,修改模型训练部分,使用LightGBM库,设置分位数回归的目标函数。需要安装lightgbm库,如果用户没有安装的话,可能需要提醒,但代码中可能已经假设安装好了。
评估指标部分,现有的MSE、RMSE、MAE、R²仍然适用,但可能需要加上分位数损失或其他指标。不过用户可能只需要替换模型,评估指标保持不变。
优化部分,目标函数还是用训练好的模型预测NO排放,寻找最小值。不过使用分位数回归模型的话,预测的是某个分位数,比如中位数,可能更稳定。或者用户可能希望预测的是较低的分位数,比如5%分位数,以找到更保守的最小排放估计。需要确认alpha参数设置,但用户可能希望保持最小化预测值,所以可能还是用默认的中位数,或者根据需求调整。
现在,分步骤思考:
1. 数据预处理阶段加入异常值过滤。例如,计算y的IQR,定义上下界,剔除超出此范围的数据点。或者使用Z-score,假设y服从正态分布,剔除3个标准差以外的点。需要确定哪种方法更合适,或者让用户选择,但代码示例中可能用IQR更常见,因为对非正态分布更稳健。
2. 替换模型为LightGBM的分位数回归。需要导入lightgbm,设置参数,objective='quantile',alpha=0.5(中位数)。可能需要调整其他超参数,如num_leaves、learning_rate等,但用户可能希望保持简单,所以先用默认参数或类似随机森林的参数。
3. 特征重要性可视化部分,LightGBM也有feature_importances_属性,可以直接使用,但可能需要用不同的可视化方式,不过原代码中的条形图应该适用。
4. 优化部分,目标函数改为调用LightGBM模型的predict方法,其他部分保持不变,因为优化过程仍然需要最小化预测值。
可能的代码修改步骤:
- 导入lightgbm库。
- 在数据预处理后,划分训练测试集前,进行异常值过滤。
- 使用IQR方法检测y中的异常值,并过滤掉对应的样本。
- 划分训练集和测试集。
- 初始化LGBMRegressor,设置objective='quantile',alpha=0.5,以及其他参数。
- 训练模型,预测,评估。
- 可视化特征重要性。
- 优化部分保持不变,只是模型换成LightGBM。
注意,分位数回归的目标函数和普通回归不同,可能会影响模型的表现,需要调整参数。同时,异常值过滤可能会减少数据量,需要检查数据量是否足够。
可能的代码调整示例:
在数据读取后:
处理异常值:
Q1 = y.quantile(0.25)
Q3 = y.quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers_mask = (y >= lower_bound) & (y <= upper_bound)
data_clean = data[outliers_mask]
X = data_clean[['掺氨比', '过量空气系数', '燃尽风位置', '主燃区温度']]
y = data_clean['NO排放浓度']
然后划分训练测试集。
模型部分:
import lightgbm as lgb
model = lgb.LGBMRegressor(
objective='quantile',
alpha=0.5, # 中位数
n_estimators=300,
max_depth=10,
min_child_samples=5,
random_state=42
)
model.fit(X_train_clean, y_train_clean)
这样替换掉原来的随机森林部分。
另外,可能需要调整参数,比如learning_rate,或者使用交叉验证来优化超参数,但用户可能希望保持代码简洁,所以暂时不加入。
评估部分保持不变,因为都是回归问题,指标仍然适用。
需要注意,分位数回归的评估可能更关注分位数损失,比如使用mean_pinball_loss,但用户可能还是希望用原来的指标,所以保持print部分不变。
最后,优化部分的目标函数调用model.predict,和之前一样。
可能还需要处理类别变量,比如'燃尽风位置'如果是分类变量,LightGBM可以自动处理,但需要设置为类别类型,或者在数据中指定categorical_feature。但原代码已经用LabelEncoder转换成数值型,所以可能没问题,但LightGBM可能会将其视为数值变量,需要确认是否正确处理。如果燃尽风位置是类别变量,即使编码成数字,应该告诉LightGBM它是类别特征,否则可能被当作连续变量处理。因此,在LightGBM中可能需要设置categorical_feature参数。
例如:
在fit的时候:
model.fit(
X_train_clean, y_train_clean,
categorical_feature=['燃尽风位置'] # 假设该列已经被编码为整数
)
但需要确认是否正确处理。或者,在数据预处理时,将该列转换为category类型:
data['燃尽风位置'] = data['燃尽风位置'].astype('category')
或者在LightGBM的数据集构造时指定:
train_data = lgb.Dataset(X_train_clean, label=y_train_clean, categorical_feature=['燃尽风位置'])
然后使用train_data来训练。但使用Scikit-learn API时,可能需要在模型初始化时指定categorical_feature参数,或者自动检测。可能需要调整这部分。
综上,修改的主要点是:
1. 异常值过滤,使用IQR方法处理y中的异常值。
2. 替换模型为LightGBM分位数回归,调整参数,处理分类变量。
3. 确保特征重要性可视化兼容。
可能需要测试代码,但用户可能希望得到可以直接替换的代码建议,所以需要将上述步骤转化为代码,并解释关键点。</think>以下是改进后的完整代码方案,使用LightGBM分位数回归结合异常值过滤:
```python
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
from scipy.optimize import minimize
import matplotlib.pyplot as plt
from pathlib import Path
import lightgbm as lgb
# ------------------ 数据预处理 ------------------
# 设置文件路径
excel_path = Path("C:/Users/Administrator/Desktop/augmented_data3.xlsx")
# 读取数据
data = pd.read_excel(excel_path, sheet_name='Sheet1')
# ------------------ 异常值过滤 ------------------
# 使用IQR方法过滤NO排放浓度异常值
Q1 = data['NO排放浓度'].quantile(0.25)
Q3 = data['NO排放浓度'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
data_clean = data[(data['NO排放浓度'] >= lower_bound) &
(data['NO排放浓度'] <= upper_bound)]
print(f"原始数据量: {len(data)}, 清洗后数据量: {len(data_clean)}")
# ------------------ 特征工程 ------------------
# 分类变量编码
le = LabelEncoder()
if data_clean['燃尽风位置'].dtype == 'object':
data_clean['燃尽风位置'] = le.fit_transform(data_clean['燃尽风位置'])
# 特征/目标变量分离
X = data_clean[['掺氨比', '过量空气系数', '燃尽风位置', '主燃区温度']]
y = data_clean['NO排放浓度']
# ------------------ 模型训练 ------------------
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# LightGBM分位数回归配置
lgb_model = lgb.LGBMRegressor(
objective='quantile', # 分位数回归目标
alpha=0.5, # 中位数回归
n_estimators=300,
max_depth=10,
min_child_samples=5,
learning_rate=0.1,
categorical_feature=['燃尽风位置'], # 指定分类特征
random_state=42
)
# 训练模型
lgb_model.fit(X_train, y_train)
y_pred = lgb_model.predict(X_test)
# ------------------ 模型评估 ------------------
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r_squared = r2_score(y_test, y_pred)
print(f'均方误差 (MSE): {mse:.2f}')
print(f'均方根误差 (RMSE): {rmse:.2f}')
print(f'平均绝对误差 (MAE): {mae:.2f}')
print(f'决定系数 (R²): {r_squared:.2f}')
# ------------------ 特征重要性可视化 ------------------
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
importances = lgb_model.feature_importances_
sorted_idx = importances.argsort()
plt.figure(figsize=(10,6))
plt.barh(X.columns[sorted_idx], importances[sorted_idx])
plt.title("LightGBM特征重要性排序")
plt.show()
# ------------------ 优化模块 ------------------
param_bounds = {
'掺氨比': (data_clean['掺氨比'].min(), data_clean['掺氨比'].max()),
'过量空气系数': (data_clean['过量空气系数'].min(), data_clean['过量空气系数'].max()),
'燃尽风位置': (data_clean['燃尽风位置'].min(), data_clean['燃尽风位置'].max()),
'主燃区温度': (data_clean['主燃区温度'].min(), data_clean['主燃区温度'].max())
}
def objective(x):
return lgb_model.predict([x])[0]
initial_guess = [
data_clean['掺氨比'].mean(),
data_clean['过量空气系数'].mean(),
data_clean['燃尽风位置'].mean(),
data_clean['主燃区温度'].mean()
]
bounds = list(param_bounds.values())
result = minimize(
fun=objective,
x0=initial_guess,
bounds=bounds,
method='L-BFGS-B'
)
if result.success:
optimal_params = result.x
min_no_emission = result.fun
print(f"最低NO排放浓度: {min_no_emission:.2f} mg/m³")
print("最优参数组合:")
print(f"掺氨比: {optimal_params[0]:.3f}")
print(f"过量空气系数: {optimal_params[1]:.3f}")
print(f"燃尽风位置: {optimal_params[2]:.1f}")
print(f"主燃区温度: {optimal_params[3]:.1f} ℃")
else:
print("优化失败,请检查约束条件或算法参数")
```
**主要改进点说明:**
1. **异常值过滤**
- 使用IQR(四分位距)方法识别并过滤NO排放浓度的异常值
- 计算公式:$ \text{下限} = Q1 - 1.5 \times IQR $,$ \text{上限} = Q3 + 1.5 \times IQR $
- 保留在$[Q1-1.5IQR, Q3+1.5IQR]$范围内的正常数据
2. **LightGBM分位数回归**
- 设置`objective='quantile'`和`alpha=0.5`实现中位数回归
- 优势:相比均值回归,对异常值具有更强的鲁棒性
- 显式指定分类特征`categorical_feature=['燃尽风位置']`
3. **模型参数优化**
- 增加`learning_rate=0.1`提升收敛速度
- 使用`min_child_samples=5`替代原来的`min_samples_split`参数
- 保留300棵决策树(`n_estimators=300`)和最大深度10(`max_depth=10`)
4. **可视化改进**
- 更新标题为"LightGBM特征重要性排序"
- 保持中文显示配置,确保图表文字正常显示
**执行建议:**
1. 确保已安装lightgbm库:`pip install lightgbm`
2. 注意检查分类变量编码后的数值范围
3. 可根据实际数据分布调整异常值过滤的IQR系数(当前使用1.5倍)
4. 可通过网格搜索进一步优化LightGBM超参数
阅读全文
相关推荐













