赛题背景
本文分享赛题来自“中国石化第一届人工智能创新大赛”,大赛由中国石油化工集团有限公司主办,聚焦能源化工产业。赛题覆盖了产业链上中下游的不同任务,包括勘探开发、炼化生产、油品销售、智能营销和智能金融等关键支撑环节。
目前大赛全部10道赛题均已上线,开放数据集下载、提交评测,来自全国顶级高校、科研院所以及人工智能领域研发企业的学者、研究人员、技术开发者将共同参与赛事角逐,集智创新。
本次大赛设置了丰厚的大赛奖励,总奖金80万元人民币,其中每个赛道奖金8万元人民币,分设一等奖、二等奖、三等奖。此外,获奖团队还将获得组委会颁发的荣誉证书,有机会获得名企实习机会,作品孵化机会等,针对应用潜力大的优秀项目团队有机会获得额外激励。
大赛官网:https://aicup.sinopec.com/?source=bl04
赛题Baseline
Baseline代码下载:https://pan.baidu.com/s/1GYcrdGEE3H1cBgmtawgW7g?pwd=smv3
今天我们主要分享“基于AI的生产装置质量指标预测”赛题。针对该赛题,我们将从以下四个方面来介绍:首先,会分享一下本次赛题的背景知识;接下来,我们会看一下赛题涉及到的相关数据;接着会介绍一些Baseline的方案,以及基于Baseline可以优化的一些思路和可能的方向;最后,会针对本次赛题进行一个简单的总结。
一、 赛题背景介绍
首先,我们来看一下本次赛题的背景介绍。本次比赛主要是为了预测一个产品的关键质量指标。这个任务在AI的应用场景中,主要是通过预测产品的关键质量指标,来提高产品在生产中的效益,或者说市场上的竞争力。
传统上对这类产品关键质量指标的监测主要是通过人工定时采样,然后将样品送到实验室进行化学分析。那么,通过人工手段有哪些缺点呢?
第一,化验过程非常耗时,导致质量监测存在显著的延时。当某个产品被发现不合格时,可能已经造成了大量的物料浪费和经济损失。因此,通过人工化验,质量监控的周期其实非常长,会浪费大量的生产物料并造成经济损失。
第二,人工采样和化验的频率是有限的,一般来说可能是一天一到两次。所以,它其实很难实时把握我们生产过程中一些瞬时的波动对产品质量的影响,这在现代化的工业场景中是一个缺陷。
随着工业互联网和AI技术的发展,通过AI与智能制造的结合,可以大大弥补我们刚才提到的缺陷。由于工业互联网的发展,大部分生产环境中都部署了大量的传感器,可以达到秒级或者分钟级的采集频率,来实时检测生产环境中的温度、压力、流量、液位等海量数据。这些数据可以不断提高我们在产品生产环境中质量监测的作用。
因此,本次赛题就是利用AI技术,通过传感器信息来预测产品的质量,从而可以实时监测质量效果,减少产品的不合格率,提高产品质量,同时也会降低对人工化验的依赖。这就是我们本次赛题的初衷,在工业互联网环境中,这类需求非常大。
本次竞赛的任务,就是依赖于传感器的过程数据,包括温度、压力、流量等,以及通过历史实验室化验得到的质量指标数据,来构建模型。我们需要设计一个模型,通过给定的历史传感器数据,对需要实时监控的指标进行建模,从而精准预测出每一个时间点对应的关键质量指标数值。这就是我们本次赛题的背景,及其在实际生产环境中的应用。
二、 数据集介绍
接下来我们看一下本次赛题提供的数据。赛题一共提供了几个数据集,包含在三个文件夹中。这些数据是生产环境中的原始数据,经过脱敏处理。数据主要分为两个部分:第一部分是过程数据,也就是传感器数据,它包含一些蒸馏数据和反应时的数据,这些数据是通过传感器进行秒级传输得到的。第二部分是化验数据,主要来源于实验室历史积累的化验结果。大家下载数据后可以看到,一共有三个这样的文件夹。
首先第一个是反应数据,这个数据包含时间戳和一系列传感器读数。它的时间数据精确到秒级,主要来源于传感器的自动传输。后面这些列是来自不同传感器的数据。虽然官方没有给出这些数据的具体物理意义,但我们其实可以大致推断它们的含义,这一点我们稍后会介绍。
第二个数据是蒸馏数据,这个数据与反应数据类似,同样是通过传感器秒级传输得到的,也包含了时间戳和一系列传感器读数。
最后一个是历史化验数据。例如,我们在某个时间点进行采样,样品是“尾油”,然后我们可以检测出它在不同阶段的流出温度、流出量等,通过样品检测得到它的分析数值。后面一列是当前点的采样时间。
从数据量上来看,前两个传感器传输的数据量比较大,有几百兆,而化验数据则相对较少。这里也描述了详细的数据信息,传感器数据是实时传输的,每一行代表一个时间点,采样频率是每30秒一次。数据文件包含两种,以train为结尾的是训练集,以validation为结尾的是验证集。我们初赛的核心任务是预测validation数据集中的分析值,所以train中的分析值是我们的训练目标(y值),而validation中的样本是我们的测试集。
关于化验数据,它的场景是这样的:我们刚才提到有采样时间,比如我们是早上7:00进行采样,那么采样得到的样品,其实是来源于这之前一段时间机器工作中产生的产品。所以,我们需要去匹配在7点之前的生产环境中的实时传感器数据。例如,我们可以去匹配早上6:00到7:00的传感器数据,这个数据就可以当作是当前样品在生产环境中的实时数据。
这份化验数据中还提供了一些指标,比如“初馏点”、“10%馏出温度”、“50%馏出温度”等不同的馏出点的温度,以及“终馏点”等内容。我们主要是预测样品在不同指标下的分析结果。最后,表里有一个“分析值”列,这个分析值其实就是我们的y值,也就是我们需要预测的目标。我们需要预测这个样品在不同指标下的分析值,这个分析值就代表了它的质量。
所以,我们的核心任务是基于化验数据中的X(采样信息)和y(分析值)来进行建模,建模之后,再根据验证集(validation)里的X来预测我们需要的y。我们把预测的y提交上去,就可以得到最终的比赛结果。化验数据同样也包含以train结尾的训练集文件和以validation结尾的验证集文件。
最后是提交格式,我们需要把validation里面的每一条ID都预测出一个预测值,然后将预测值按照指定的CSV格式进行提交,文件以逗号为分割。这就是我们整体的数据介绍,大家可以去官网上直接下载数据。
本次比赛使用的评价指标是MAPE,即平均绝对百分比误差。MAPE是衡量预测值与实际值之间差异的一个指标。我们预测的是一个数值,所以我们用当前真实值减去它的预测值,再除以真实值,然后取绝对值,以此作为衡量结果的指标。当真实值跟预测值越来越接近时,代表我们预测的效果越来越好,整个模型效果也就会越来越好。所以,如果大家的MAPE值越来越小,就代表模型效果越来越好。大家需要注意本次比赛的评价指标,因为在不同的赛题里,评价指标和优化目标都可能不一样。
三、Baseline方案构建
整体数据介绍完之后,我们接下来看一下如何构建一个Baseline。
构建Baseline的过程主要分为以下几个部分:首先是数据理解和处理;其次是数据分析,这可能需要大家有一些业务知识的了解,比如分析蒸馏过程和反应过程中的数值对我们最终分析值(y值)的影响;接下来是特征构造的过程,我们将探讨如何构造特征;最后是建模,选择使用机器学习模型还是时序模型。
1.数据理解与分析
这个过程就是对我们刚才讲到的数据做一些简单的分析。我们最终的输入是X和y,这两张表非常重要,一张是反应传感器得到的数据,另一张是蒸馏时传感器得到的数据。这两个数据主要用于我们本次赛题的特征构建,因为传感器的传输数据会影响最终样品的质量,对我们的X有一个影响。
我们首先看一下我们的X。它是根据“样品”以及当前的“组份”得到它的y值。所以,“样品”和“组份”这两个字段你可以认为是我们的ID。而y值就是分析值,比如我们要预测“尾油”在“10%馏出温度”这个组份下的分析值是311.40摄氏度,这就是一个X和y的构建。
为了更好地优化赛题,大家可能需要了解一下各个组份的含义。比如,“初馏点”代表第一滴馏出液出现的温度;后面是10%、30%、50%、70%、90%等不同百分比的馏出液体积对应的温度。大家可以看到,随着馏出百分比不断升高,它的温度也是不断变大的。后面还会预测一些“全馏量”(单位是毫升),以及一些“残留量”等等。所以,大家需要了解组份的含义。
另外一个是“样品”字段,它其实是采集了不同生产阶段的样品,比如“尾油”、“常二线”、“煤油”、“航煤”等。我们需要理解X和y的关系,分析值就是不同组份下的一个结果。我们的核心任务是,当拿到一个样品和组份时,预测它对应的分析值是多少。
举个例子,以“初馏点”为例,它预测的分析值(比如231度)其实是会受到蒸馏传感器和反应传感器的信息影响的。假如我们当前采样时间是早上7点,我们就会根据传感器的一个时间窗口,比如早上5:30到7点这个窗口内的传感器数据,来判断它的初馏点温度是多少。因此,我们就需要用到传感器数据表。我们需要看到当前时间点往前推90分钟,或者两个小时,或者一个小时的传感器变化,这个窗口大小取决于自己对于特征的构建。
根据一些实际生产环境的经验,在不同的馏出温度下,它所依赖的蒸馏时间窗口其实是不一样的。比如,后面的一些高馏出温度,可能受到前面更长时间段的传感器窗口的影响。而对于反应窗口而言,它同样也有一个影响窗口。比如早上7点采样,可能往前推10分钟到两个小时的反应窗口数据,对于“初馏点”的影响是比较大的。
这个“窗口”的选择,是本次赛题一个非常关键的部分,它对于最终结果的影响非常大。另外,对于不同的样品类型,这个窗口的大小其实也是有变化的,这个大家可以在后面去探索。
在我们构建Baseline时,可以先用一个统一的窗口。比如,蒸馏窗口我们统一使用采样前的两个小时,反应窗口我们使用采样前180分钟到10分钟这个区间。
当我们选定了窗口之后,就可以得到这样的一个数据结果。比如,当前采样是早上7点,我们就可以拿到往前90分钟内传感器传输过来的数据变化。比如,T3000.PV这个特征,在90分钟的窗口内,它会有一系列的值。右边是反应传感器的数据,比如我们是早上7点采样,就往前推10分钟到两个小时,可以看到T2000.PV这个特征下,它的一个变化结果。
有时候,我们可以通过特征的名称来推断它的物理含义。比如以T开头的特征,官方虽然说做了匿名处理,但我们有时可以推断出T可能代表温度(Temperature)的简称。同理,P可能是压力(Pressure),F可能是流量(Flow),R可能是一个比值或者回流(Ratio/Reflux)。理解特征的含义有什么作用呢?它主要是帮助我们后面做特征交叉。例如,如果T开头的都是温度,我们就可以计算不同位置上传感器的温差,以此来判断温度变化的影响。
2.特征工程
基于我们刚刚构建的这些窗口内的数据,我们就可以做一些特征了。我们知道,“样品”和“组份”这两个ID本身就可以作为特征。同时,官方也提到,采样时间和之前的传感器传输时间是高度相关的。那么,我们就需要基于采样时间往前推一个窗口(比如90分钟或两个小时),来得到传感器的时序特征。
基于这个时间窗口内的特征,我们需要做一些聚合操作。这里我们罗列了一些常用的特征聚合方法,它们可以表示特征的分布、最大最小变化,衡量这个时间窗口内波形图的变化。例如:
均值或标准差:可以衡量传感器在这个阶段的波动性和稳态。
分位数:可以统计它的分布形状。
极大值/极小值:可以判断是否存在越界风险,比如温度过高或过低,可能会严重影响样品的质量。
滚动均值或滚动标准差:可以探索不同时间尺度下特征的影响。
我们还可以做一些特征交叉。刚才我们提到了,可以推断出特征的类型。比如,有很多以T为开头的特征,我们假设它们都是温度,那么T3000和T3002很可能是安装在不同位置上的传感器,返回不同位置的温度。这样,我们就可以统计不同位置上的温度变化,比如计算一些顶温和塔板温的差值,再对这个差值进行统计,这就是一个特征交叉的过程。
3. Baseline代码实现
我们来看一下我们的Baseline是如何构建的。这里我写了一份Baseline的代码。
首先,需要下载官方文件,解压之后可以看到这样的目录结构。其中主要有三个用于训练的数据文件:一个是反应传感器的训练数据,一个是蒸馏的传感器数据,以及我们的训练集X和y。我们需要预测的是验证集的y,并且提供了一个提交样例。
接下来,我们需要导入一些库。这里我们主要选择基于机器学习的方法,做一些特征工程,然后实现模型的构建。我们用到了LightGBM这个模型,它在机器学习比赛中是一个比较常用的树模型,泛化能力比较强。
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from lightgbm import LGBMRegressor
from sklearn.model_selection import KFold, cross_val_predict
from sklearn.metrics import mean_absolute_percentage_error
第一步是读取数据,主要读取训练集和验证集的数据,总共有6个文件。读取完成后,需要做一些数据处理。这里我们对y值做了一些处理,判断并去掉了一些异常值。然后,我们把样本中的中文列名转化成英文列名,便于后续代码处理,比如“采样时间”改为sample_time,“分析值”改为value等。
analysis_train = pd.read_csv("train+validation+sample /analysis_train.csv")
analysis_validation_without_truth = pd.read_csv("train+validation+sample /analysis_validation_without_truth.csv")
distillation_process_train = pd.read_csv("train+validation+sample /distillation_process_train.csv")
distillation_process_validation = pd.read_csv("train+validation+sample /distillation_process_validation.csv")
reaction_process_train = pd.read_csv("train+validation+sample /reaction_process_train.csv")
reaction_process_validation = pd.read_csv("train+validation+sample /reaction_process_validation.csv")
def is_numeric(value):
try:
float(value)
return True
except (ValueError, TypeError):
return False
analysis_train = analysis_train[analysis_train["分析值"].apply(is_numeric)]
接着,我们对sample_time列做了一个时间类型的转化和排序。
# 1) 统一字段名(中文→英文便于处理)
rename_map = {"采样时间":"sample_time","组分":"component","分析值":"value","采样点":"sample_point","样品":"sample"}
analysis_train = analysis_train.rename(columns={c: rename_map.get(c,c) for c in analysis_train.columns})
analysis_validation_without_truth = analysis_validation_without_truth.rename(columns={c: rename_map.get(c,c) for c in analysis_validation_without_truth.columns})
analysis_train["sample_time"] = pd.to_datetime(analysis_train["sample_time"], errors="coerce")
analysis_validation_without_truth["sample_time"] = pd.to_datetime(analysis_validation_without_truth["sample_time"], errors="coerce")
# 过程表:把“时间”→ timestamp,并排好序
for df in (distillation_process_train, distillation_process_validation, reaction_process_train, reaction_process_validation):
df.rename(columns={"时间":"timestamp"}, inplace=True)
df["timestamp"] = pd.to_datetime(df["timestamp"], errors="coerce")
df.dropna(subset=["timestamp"], inplace=True)
df.sort_values("timestamp", inplace=True)
df.drop_duplicates(subset=["timestamp"], inplace=True)
df.reset_index(drop=True, inplace=True)
处理好X和y的数据之后,我们需要来构造特征。我们知道,传感器数据表和化验数据表之间的关联是通过“采样时间”来实现的。我们需要对采样时间设定一个窗口,我们认为在这个窗口内的传感器数据对于我们的y值是有意义的。这里设定了两个窗口,一个是蒸馏窗口,一个是反应窗口。
# 2) 固定窗口(简化):蒸馏 [T-120, T];反应[T-180, T-10]
WD, OD = 120, 0
WR, OR = 180, 10
然后,我们把需要用到的传感器特征列名提取出来,比如蒸馏的特征列和反应的特征列。
# 3) 选数值型传感器列(排除 timestamp 等)
ignore = {"timestamp"}
d_cols_tr = [c for c in distillation_process_train.columns if c not in ignore ]
r_cols_tr = [c for c in reaction_process_train.columns if c not in ignore ]
d_cols_va = [c for c in distillation_process_validation.columns if c not in ignore ]
r_cols_va = [c for c in reaction_process_validation.columns if c not in ignore ]
# 统一列集合(避免推理缺列)
d_cols = sorted(list(set(d_cols_tr) & set(d_cols_va)))
r_cols = sorted(list(set(r_cols_tr) & set(r_cols_va)))
接下来就到了核心的过程。我们首先需要把所有的时间数据取出来,然后将这个时间数据与我们的反应传感器数据和蒸馏传感器数据进行关联。我们写了一个函数来实现这个关联。这个函数会拿到每个样本的采样时间t,然后根据设定的窗口大小,计算出开始时间和结束时间,再用这个时间窗口对反应和蒸馏数据进行切片,我们认为这个时间段内的数据对t时刻的样本是有作用的。
之后就到了特征构建的核心函数。我们需要对切片出来的反应时间和蒸馏时间数据进行特征构建。在这里,我们主要构建了三个例子性的特征:第一个是当前窗口内数据的平均值,第二个是它的方差,以及第三个是传感器在窗口内最后一个时刻的数据。也就是说,我们对这个时间窗口内的数据求了均值和方差,并且还取了最后一个时刻的值。大家如果后面想做一些探索,可以在这里增加更多的特征,来反映整个窗口内的曲线变化。构建好的特征,我们把它聚合到一个字典里。
def build_feature_row(
T, distill_df, react_df, d_cols, r_cols,
WD=120, OD=0, WR=180, OR=10, target=np.nan, row_id=None
):
if pd.isna(T):
return None
# 窗口
d_start, d_end = T - pd.Timedelta(minutes=WD), T - pd.Timedelta(minutes=OD)
r_start, r_end = T - pd.Timedelta(minutes=WR), T - pd.Timedelta(minutes=OR)
# 切片
d_seg = distill_df[(distill_df["timestamp"]>=d_start) & (distill_df["timestamp"]<=d_end)]
r_seg = react_df[(react_df["timestamp"]>=r_start) & (react_df["timestamp"]<=r_end)]
def stats_block(seg, cols, prefix):
# 只用交集列,避免“补出来”的空列
use_cols = [c for c in cols if c in seg.columns]
if len(use_cols) == 0 or seg.empty:
return {f"{prefix}{c}_{s}": np.nan for c in cols for s in ["mean","std","last"]} | {
f"{prefix}points": 0
}
# 转数值(把'—'、'NULL'、'开/关'等都变成 NaN 或数字后再算)
blk = seg[use_cols].apply(pd.to_numeric, errors="coerce")
m = blk.mean().add_prefix(prefix).add_suffix("_mean")
s = blk.std().add_prefix(prefix).add_suffix("_std")
l = blk.iloc[-1].add_prefix(prefix).add_suffix("_last")
return (pd.concat([m, s, l]).to_dict() |
{f"{prefix}points": len(blk)})
feats = {
"sample_time": T
}
feats.update(stats_block(d_seg, d_cols, "d_"))
feats.update(stats_block(r_seg, r_cols, "r_"))
return feats
analysis_train_sample_time = (analysis_train
.sort_values("sample_time")
.drop_duplicates(subset=["sample_time"], keep="last")
.reset_index(drop=True))
print("去重后行数:", len(analysis_train_sample_time))
train_dicts = (analysis_train_sample_time.dropna(subset=["sample_time"])
.apply(lambda r: build_feature_row(
T=r["sample_time"],
distill_df=distillation_process_train,
react_df=reaction_process_train,
d_cols=d_cols, r_cols=r_cols,
WD=WD, OD=OD, WR=WR, OR=OR
), axis=1))
train_feats = pd.DataFrame([d for d in train_dicts if d is not None]).sort_values("sample_time")
特征构建完成后,我们用Pandas把它变成一个DataFrame数据类型。然后,我们选择哪些特征是我们需要的。这里我们主要把自己提取出来的特征,以及两个ID类特征——sample(样品)和component(组份)——都作为我们的特征。因为在特定样品和组份下,传感器的状态对y值有非常直接的影响,所以这两个ID特征也非常重要。
train_df = analysis_train[["id","sample_time","sample","component","value"]].merge(train_feats, on="sample_time", how="inner")
# 拆出特征/标签
feature_cols = [c for c in train_df.columns if c.startswith(("d_","r_"))] + ["sample","component"]
X_train = train_df[feature_cols]
y_train = train_df["value"]
以同样的方式,我们对验证集也进行同样的处理,构造出相同的特征。
analysis_validation_sample_time = (analysis_validation_without_truth
.sort_values("sample_time")
.drop_duplicates(subset=["sample_time"], keep="last")
.reset_index(drop=True))
print("去重后行数:", len(analysis_validation_sample_time))
val_dicts = (analysis_validation_sample_time.dropna(subset=["sample_time"])
.apply(lambda r: build_feature_row(
T=r["sample_time"],
distill_df=distillation_process_validation,
react_df=reaction_process_validation,
d_cols=d_cols, r_cols=r_cols,
WD=WD, OD=OD, WR=WR, OR=OR
), axis=1))
构造完成后,接下来就是模型的训练。由于线上提交次数有限,大家可以先做一些线下的验证。这里我们用到了scikit-learn里的交叉验证函数,进行5折交叉验证,并计算出MAPE值。大家可以在增加更多特征后,先跑一下这个线下验证,看看效果有没有提升。如果线下效果比较好,可能线上效果也会有提升。大家可以观察一下线下交叉验证的结果和线上的结果是不是同增同减的。从目前来看,通过交叉验证得到的MAPE和线上的MAPE其实是有一点差距的。
cat_cols = ["sample","component"]
feature_cols = [c for c in train_df.columns if c.startswith(("d_","r_"))] + ["sample","component"]
X_train = X_train[feature_cols].copy() # 包含数值特征 + 这两列
for c in cat_cols:
X_train[c] = X_train[c].astype("category") # 关键:设为分类 dtype
kf = KFold(n_splits=5, shuffle=True, random_state=42)
est = LGBMRegressor()
pred = cross_val_predict(est, X_train, y_train.astype(float), cv=kf, n_jobs=-1)
print("MAPE (ε=1e-3):", mean_absolute_percentage_error((y_train.astype(float)).clip(lower=1e-3),
pred.clip(min=1e-3)))
如果想跑一个线上提交的版本,我们可以用全部训练数据训练一个LightGBM模型。因为我们是预测数值,所以用LGBMRegressor。模型训练完成后,我们就可以对验证集进行预测,最后把结果保存成线上需要的格式,即一个包含ID和预测值(predict)的CSV文件,然后进行提交。
X_val = X_val[feature_cols].copy() # 包含数值特征 + 这两列
for c in cat_cols:
X_val[c] = X_val[c].astype("category") # 关键:设为分类 dtype
model = LGBMRegressor()
model.fit(X_train, y_train.astype(float), categorical_feature=cat_cols)
pred = model.predict(X_val)
pd.DataFrame({"id": val_df["id"], "predict": pred.astype(int)}).to_csv("result.csv", index=None)
这个Baseline提交后,分数大概是10点几。因为我们没有用到很多特征,也没有做很多优化,所以这个分数是一个非常正常的状态。大家后面增加更多的特征之后,效果是可以达到一个比较好的水平的。
四、 优化思路与总结
Baseline讲完之后,我们来看一下这个赛题有哪些可以优化的方向。
首先,在特征工程这块,我们只用到了均值和标准差。大家其实可以增加一些其他的特征,比如我们之前提到的分位数、最大/最小值等,来更好地衡量区间内的变化。这是第一个优化点。
第二点,我们刚才使用的窗口是一个固定的窗口。在不同的组份下,所依赖的窗口大小其实是不同的。如果大家没有相关的业务知识,可以怎么做呢?我们可以增加一个多尺度的窗口。例如,我们可以同时使用0-90分钟、0-120分钟、0-180分钟等不同尺度的窗口来提取特征,衡量不同时间尺度下的变化。对于反应窗口也是一样的。
第三个更深入的优化,是做一些交叉特征。比如,我们假设T开头的特征是温度,那么我们可以做一些特定位置的传感器温度减去另一个传感器温度的特征,来衡量它们之间的关系。大家可以自己线下探索这些特征的物理含义。一般来说,同一种前缀(如T, P, F, L, R, Z)的特征代表同一种物理量,我猜测它们是英文单词的首字母。大家可以增加一些特征交叉的变化,因为不同位置上传感器的前后关系,比如温度的变化,对于产品质量是有非常大影响的。
第四个优化点是在模型层面。我们使用的是默认参数的LightGBM,大家可以测试一下不同模型参数的影响,进行调参。
第五点,可以做一些不同模型的融合。大家可以尝试使用其他机器学习模型,甚至是一些时间序列模型,然后做模型融合。
此外,我们这里其实有很多特征,后面可以做一些特征筛选,因为有些特征可能没有作用或者作用不是很大。比如,我们可以看到一些以R或Z开头的特征,它们的取值可能是0或1,这可能代表了一些阀门的开关状态,大家需要去理解一下这些特征简单的物理含义。
最后,我们来简单总结一下本次赛题。
如果大家想在Baseline上做一些提升,首先要对数据和业务进行理解,然后构造有效的特征。
目标明确:我们的X的ID是“样品”和“组份”,预测目标是“分析值”,评价指标是MAPE。
特征构造:大家要注意,构造特征时,比如采样时间是早上7点,我们只能用这个时间点之前的传感器数据。所以,特征很明显是基于一个时间窗口内的数据变化来构造的。
物理含义推断:我们简单推理了T/P/F/L/R/Z可能分别代表温度、压力、流量、液位、阀位、状态,大家可以再验证一下。
特征类型:
基础特征:我们只用到了平均值和方差,大家可以用更多特征,如最大值、最小值、极差以及一些平滑特征来构建。
交叉特征:当了解了关键信号后,可以构建交叉特征,比如不同位置的温度差、压力变化等。
窗口选择:我们用了固定窗口,大家可以尝试对不同组份使用不同窗口,或者使用多尺度的窗口。
模型优化:
模型选择:可以探索不同的机器学习或深度学习模型。
模型融合:不同模型有不同的表示能力,可以做模型融合。
参数调优:可以对模型进行调参。
验证策略:最后,结合交叉验证,对比线下和线上的效果,探索它们是否同增同减。
以上就是我们整体的赛题介绍、Baseline方案介绍,以及后续可能的一些优化空间的分享。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.