赛题介绍
赛事任务
初赛任务:初赛提供了电炉17个温区的实际生产数据,分别是电炉上部17组加热棒设定温度T1-1~T1-17,电炉下部17组加热棒设定温度T2-1~T2-17,底部17组进气口的设定进气流量V1-V17,选手需要根据提供的数据样本构建模型,预测电炉上下部空间17个测温点的测量温度值。
数据说明
初赛为参赛选手提供了5类数据:1)加热棒上部温度设定值、2)加热棒下部温度设定值、3)进气流量、4)上部空间测量温度、5)下部空间测量温度。出于数据安全保证的考虑,所有数据均为脱敏处理后的数据。训练集及测试集每行均含有5类数据。选手需要建立上部加热棒设定温度、下部加热棒设定温度、进气流量与上部空间测量温度、下部空间测量温度之间的模型。
评估指标
初赛考核办法采用测试集各行数据的加热棒上部温度设定值、加热棒下部温度设定值、进气流量3类数据作为输入,选手分别预测上部空间测量温度、下部空间测量温度。将选手预测的上部空间测量温度、下部空间测量温度与测试集数据的测量值进行比较。采用MAE平均绝对误差作为评价指标。
赛题分析
- 本赛题的背景是锂离子电池的生产过程,涉及到电炉的温度控制和温度预测,这是一个具有实际意义和工业价值的问题。
- 本赛题的难点可能在于如何利用有限的数据样本,建立一个准确和稳定的回归模型,同时考虑到电炉的空间分布和时序变化。
- 本赛题的特点是数据集较小,这意味着模型可能容易过拟合或欠拟合,需要进行合适的特征工程和模型选择。
- 本赛题的思路可能有以下几种:
- 基于传统的机器学习方法,如线性回归、岭回归、支持向量机、决策树、随机森林等,对每个目标变量单独建立一个回归模型,然后将所有模型的预测结果汇总。这种方法简单易实现,但可能忽略了不同目标变量之间的相关性和影响因素。
- 基于深度学习方法,如多层感知机、卷积神经网络、循环神经网络、长短期记忆网络、注意力机制等,对所有目标变量建立一个统一的回归模型,然后输出一个34维的向量作为预测结果。这种方法可以利用深度学习的强大表达能力,同时考虑到电炉的空间结构和时序特征,但可能需要更多的数据和计算资源,以及更多的调参和优化。
- 基于集成学习方法,如梯度提升树、XGBoost、LightGBM、CatBoost等,对每个目标变量单独或同时建立一个回归模型,然后将所有模型的预测结果加权平均或投票。这种方法可以结合多个弱学习器的优势,提高模型的准确性和鲁棒性,同时可以进行特征重要性分析和参数调优。
LightGBM模型
模型概况
LightGBM模型是一个基于梯度提升决策树(GBDT)的机器学习框架,它可以用于回归、分类、排序等任务。
- 数据预处理
- 切分训练集与验证集
- 训练模型
- 生成最后的预测结果
一般步骤
- 读入数据,划分训练集、验证集和测试集,转换为LightGBM的Dataset格式。
- 定义模型的超参数,如任务类型、提升方法、目标函数、树的深度、叶子数、学习率等。
- 使用LightGBM的train函数训练模型,可以使用回调函数(callback)来实现早停(early stopping)、日志记录(log evaluation)等功能。
- 使用LightGBM的predict函数预测测试集的结果,评估模型的性能,如均方误差(MSE)、平均绝对误差(MAE)、平均绝对百分比误差(MAPE)等指标。
- 对模型进行优化,如调整目标函数和评估函数,使用网格搜索(Grid Search)或贝叶斯优化(Bayesian Optimization)等方法寻找最优的超参数组合。
Baseline代码
- 教程Baseline网址【来自Datawhale七月AI夏令营】
- 教程Baseline代码【来自Datawhale七月AI夏令营】
# 导入所需的库
import pandas as pd # 读取和处理csv文件的数据
# 用于处理数据的工具,常用于数据加载、数据清洗和数据预处理
import lightgbm as lgb # 机器学习模型 LightGBM
# 构建梯度提升树模型,是一种高效的机器学习算法
from sklearn.metrics import mean_absolute_error # 评分 MAE 的计算函数
# 从sklearn.metrics模块中导入评分函数
# 平均绝对误差(MAE),是用于回归问题的一个评价指标
from sklearn.model_selection import train_test_split # 拆分训练集与验证集工具
# 用于将数据集拆分为训练集和验证集,以便进行模型训练和评估
# sklearn.model_selection对机器学习模型进行参数调优、数据集拆分、交叉验证和性能评估等任务
# train_test_split函数,将数据集划分为训练集和测试集,并且可以灵活地设置拆分比例和随机种子
from tqdm import tqdm # 显示循环的进度条工具
# 循环过程显示进度条,方便查看代码执行进度
# 数据准备
train_dataset = pd.read_csv("./data/train.csv") # 原始训练数据。
test_dataset = pd.read_csv("./data/test.csv") # 原始测试数据(用于提交)。
submit = pd.DataFrame() # 定义提交的最终数据。
submit["序号"] = test_dataset["序号"] # 对齐测试数据的序号,确保与原测试数据的一致性
MAE_scores = dict() # 定义评分项。
# 模型训练
pred_labels = list(train_dataset.columns[-34:]) # 需要预测的标签。
# 训练数据集的最后34列是需要预测的目标变量
train_set, valid_set = train_test_split(train_dataset, test_size=0.2) # 拆分数据集。
# 设定 LightGBM 训练参,查阅参数意义:https://lightgbm.readthedocs.io/en/latest/Parameters.html
lgb_params = {
'boosting_type': 'gbdt',
'objective': 'regression',
'metric': 'mae',
'min_child_weight': 5,
'num_leaves': 2 ** 5,
'lambda_l2': 10,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'bagging_freq': 4,
'learning_rate': 0.05,
'seed': 2023,
'nthread' : 16,
'verbose' : -1,
}
# 调整参数是优化模型性能的重要手段
no_info = lgb.callback.log_evaluation(period=-1) # 回调函数no_info,禁用训练日志输出。
# LightGBM通常会输出一些训练过程的信息,通过回调函数可以避免输出这些信息,使得训练过程更简洁
def time_feature(data: pd.DataFrame, pred_labels: list=None) -> pd.DataFrame:
"""提取数据中的时间特征。
输入:
data: Pandas.DataFrame
需要提取时间特征的数据。
pred_labels: list, 默认值: None
需要预测的标签的列表。如果是测试集,不需要填入。
输出: data: Pandas.DataFrame
提取时间特征后的数据。
"""
data = data.copy() # 复制数据,避免后续影响原始数据。
data = data.drop(columns=["序号"]) # 去掉”序号“特征。
data["时间"] = pd.to_datetime(data["时间"]) # 将”时间“特征的文本内容转换为 Pandas 可处理的格式。
data["month"] = data["时间"].dt.month # 添加新特征“month”,代表”当前月份“。
data["day"] = data["时间"].dt.day # 添加新特征“day”,代表”当前日期“。
data["hour"] = data["时间"].dt.hour # 添加新特征“hour”,代表”当前小时“。
data["minute"] = data["时间"].dt.minute # 添加新特征“minute”,代表”当前分钟“。
data["weekofyear"] = data["时间"].dt.isocalendar().week.astype(int) # 添加新特征“weekofyear”,代表”当年第几周“,并转换成 int,否则 LightGBM 无法处理。
# 转换成int整数类型,否则LightGBM无法处理
data["dayofyear"] = data["时间"].dt.dayofyear # 添加新特征“dayofyear”,代表”当年第几日“。
data["dayofweek"] = data["时间"].dt.dayofweek # 添加新特征“dayofweek”,代表”当周第几日“。
data["is_weekend"] = data["时间"].dt.dayofweek // 6 # 添加新特征“is_weekend”,代表”是否是周末“,1 代表是周末,0 代表不是周末。
data = data.drop(columns=["时间"]) # LightGBM 无法处理这个特征,它已体现在其他特征中,故丢弃。
if pred_labels: # 如果提供了 pred_labels 参数,则执行该代码块。
data = data.drop(columns=[*pred_labels]) # 去掉所有待预测的标签。
return data # 返回最后处理的数据。
test_features = time_feature(test_dataset) # 处理测试集的时间特征,无需 pred_labels。
# 从所有待预测特征中依次取出标签进行训练与预测。
for pred_label in tqdm(pred_labels):
train_features = time_feature(train_set, pred_labels=pred_labels) # 处理训练集的时间特征。
train_labels = train_set[pred_label] # 训练集的标签数据。
train_data = lgb.Dataset(train_features, label=train_labels) # 将训练集转换为 LightGBM 可处理的类型。
valid_features = time_feature(valid_set, pred_labels=pred_labels) # 处理验证集的时间特征。
valid_labels = valid_set[pred_label] # 验证集的标签数据。
valid_data = lgb.Dataset(valid_features, label=valid_labels) # 将验证集转换为 LightGBM 可处理的类型。
# 训练模型,参数依次为:导入模型设定参数、导入训练集、设定模型迭代次数(200)、导入验证集、禁止输出日志
model = lgb.train(lgb_params, train_data, 200, valid_sets=valid_data, callbacks=[no_info])
valid_pred = model.predict(valid_features, num_iteration=model.best_iteration) # 选择效果最好的模型进行验证集预测。
test_pred = model.predict(test_features, num_iteration=model.best_iteration) # 选择效果最好的模型进行测试集预测。
MAE_score = mean_absolute_error(valid_pred, valid_labels) # 计算验证集预测数据与真实数据的 MAE。
MAE_scores[pred_label] = MAE_score # 将对应标签的 MAE 值 存入评分项中。
submit[pred_label] = test_pred # 将测试集预测数据存入最终提交数据中。
submit.to_csv('submit_result.csv', index=False) # 保存最后的预测结果到 submit_result.csv。
print(MAE_scores) # 查看各项的 MAE 值。
- 代码解析
from sklearn.metrics import mean_absolute_error # 评分 MAE 的计算函数
from sklearn.model_selection import train_test_split # 拆分训练集与验证集工具
from tqdm import tqdm # 显示循环的进度条工具
pip install scikit-learn
【sklearn模块的导入】
pred_labels
是一个列表,包含了 34 个需要预测的标签的列名,这些标签可能是分类或者回归的目标变量。train_test_split
是一个函数,用来将数据集随机分成两部分,一部分作为训练集,一部分作为验证集。test_size=0.2
表示验证集占总数据集的 20%。train_set
和valid_set
是两个数据框,分别存储了训练集和验证集的数据,包括特征和标签。train_dataset.columns
是一个索引对象,包含了数据框的所有列名。[-34:]
是一个切片操作,表示从倒数第 34 列开始到最后一列结束的所有列。list()
是一个函数,用来将索引对象转换成一个列表,方便后续操作。train_test_split
是一个函数,来自于sklearn.model_selection
模块,用于数据集的拆分。train_dataset
是一个数据框,作为函数的第一个参数,表示要拆分的数据集。test_size=0.2
是一个关键字参数,表示验证集占总数据集的比例,可以是一个浮点数或者一个整数。
- 通过调参的过程来寻找最佳的参数组合,可以使用网格搜索、随机搜索、贝叶斯优化等方法来进行。
- 一般来说,可以先固定一些不太敏感的参数,然后调整一些比较重要的参数,比如
num_leaves
、learning_rate
、feature_fraction
等,观察模型的表现,然后再细化调整其他参数。 - 调参的目标是在保证模型的泛化能力的同时,提高模型的准确性和效率。
LightGBM的数学原理
XGBoost
传统集成学习中,两类典型的集成学习框架:
- Boosting系列算法的基学习器往往是串行形成
- 例如有n个学习器,第n个学习器,是基于上一轮的学习器去进行一个迭代式的优化生成
- AdaBoost:这是一种最经典的boosting算法,它通过调整训练数据的权重分布,使得每个弱分类器都关注上一轮分类错误的样本,然后通过加权投票的方式将弱分类器组合起来。AdaBoost可以用于二分类或多分类问题。【侧重于数据而非特征】
- GBDT:这是一种基于梯度提升的boosting算法,它通过使用损失函数的负梯度作为残差来拟合每个弱分类器,从而不断减少整体的损失。GBDT可以用于回归或分类问题。
- XGBoost:这是一种优化的GBDT算法,它在GBDT的基础上引入了正则化项,以防止过拟合,同时使用了并行计算和剪枝等技术来提高效率和性能。XGBoost也可以用于回归或分类问题。
- 例如有n个学习器,第n个学习器,是基于上一轮的学习器去进行一个迭代式的优化生成
- Bagging系列算法(例如随机森林)往往是并行形成
- 学习器和学习器之间没有必然的联系,并行生成学习器
- Boosting算法与决策树结合,如何更好的将特征融入进去
- 2017年陈天奇提出XGBoost,成为当时监督学习任务的SOTA方法(最好方法)
集成学习的本质将若干个学习器组合起来,进行投票
- 决策树是一种基于树结构的分类和回归算法,它可以根据一组特征和规则,将数据集划分为不同的类别或者预测输出值。决策树有三种主要的算法:ID3、C4.5和CART。它们的区别和特点如下:
- ID3算法是最早提出的决策树算法,它使用信息增益作为特征选择的标准,选择信息增益最大的特征作为分裂节点。ID3算法的优点是简单直观,缺点是容易过拟合,没有考虑连续特征和缺失值,对取值多的特征有偏好。
- C4.5算法是在ID3算法的基础上进行了改进,它使用信息增益率作为特征选择的标准,以克服信息增益对取值多的特征的偏好。C4.5算法还引入了悲观剪枝策略,可以对生成的决策树进行后剪枝,以减少过拟合的风险。C4.5算法还可以处理连续特征和缺失值。
- CART算法是另一种流行的决策树算法,它使用基尼系数作为特征选择的标准,选择基尼系数最小的特征作为分裂节点。CART算法生成的是二叉树,每个节点只有两个分支,这样可以简化决策树的规模和计算量。CART算法既可以用于分类问题,也可以用于回归问题。【CART学习器使用的最多】【既可以做分类,也可以做回归】
- 一个集成系统,有k个基学习器,表示每一个基学习器,针对输入的自变量做分类,将个学习器集成起来,是最终投票的一个结果
- 根据树的分支规则,给出一个评分函数,是树上不同节点的权重分数
提升集成学习模型的性能
误差优化:给定一个数据分布的情况下,无论多么好的函数或者模型去进行拟合,总会产生一个误差
,以往是让预测值不断逼近,但可以考虑对残差进行优化,将其看作一个凸优化问题,求最小值
回归与误差本质可以相互转化
梯度与偏导、导数本质上是互通的
- 贪心搜索:每一轮迭代,误差都是最小的
- 启发式搜索:智能优化的一些算法,例如遗传算法或者粒子群算法
XGBoost是机器学习的一个里程碑:
- 优化梯度,提升准确度
- 自主处理数据缺失,削弱预处理困难
- 自主感知数据稀疏,减少人工降维工作量
造成数据稀疏原因:
- 缺失值
- 特定常数的频繁出现(比如大量0)
- 某些特征工程手段(比如独热编码,一列变多列,大大扩充了数据的维度)
XGBoost优点:【以层为单位】
- 二阶泰勒展开提高精度
- 正则化方法更稳健
- 借鉴随机森林方法,其中因入列抽样,降低过拟合
- 稀疏自主感知
- 对Cache使用进行优化,数据块大小提高读写速度
- 近似分支算法(level-wise)支持并行化训练
XGBoost问题:
- 精确贪心算法需要反复迭代反复遍历,计算量和内存消耗都很大
- level-wise策略增长可能带来很多不必要的叶子节点
- 尽管cache感知,但仍有大量cache missing,造成页面调度空间过大
LightGBM
LightGBM主要优化点:【以节点为单位】
- 基于Histogram(直方图)的决策树算法
- 带深度限制的(防止过深、过拟合)的Leaf-wise(特点节点为单位)的叶子生长策略
- 直方图做差加速
- 直接支持类别特征(不需要独热编码)
- Cache命中率优化(进一步提升运算速度和可并行性)
- 基于直方图的系数特征优化
- 多线程优化
LightGBM主要方法:
- 直方图算法
- 数据并行与特征并行
- GOSS梯度采样
- EFB方法
直方图算法
先对特征值做装箱处理,本质上是一个分段函数(对每个特征的取值做个分段函数,将所有样板在该特征上的取值划分到某一段bin中)。最终把特征取值从连续值转化成了离散值。遍历数据时,根据离散化后的值作为索引在直方图中累计统计量。当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点【连续值变离散,模糊化的处理】
例如,一列0~1的浮点数,将其分段,[0,0.3)0,[0,3,1)1,即将连续值改写成离散值0和1,即为装箱
行数乘以列数优化到区段数乘以特征数
数据并行与特征并行
数据决定上限,模型逼近上限,特征往往不会冗余,数据会冗余
GOSS(单边)梯度采样
EFB方法
并行方式
LightGBM实操
不论是决策树还是集成学习,或者梯度提升的框架,一颗树的节点表示的是分割的规则,阈值划分,给出规则形式,以及叶子节点的权重分数(本质上贪心过程)