暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kaggle比赛总结:Heat Flux 缺失值填充

Coggle数据科学 2023-09-18
242
  • 赛题名称:Feature Imputation with a Heat Flux Dataset
  • 赛题类型:对数据集中缺失值进行填充
  • 赛题链接👇:

https://www.kaggle.com/competitions/playground-series-s3e15/

比赛介绍

本次比赛的数据集(包括训练和测试数据)是通过对“预测临界热通量数据集”进行深度学习模型训练而生成的。特征分布与原始数据接近,但不完全相同。您可以自由使用原始数据集作为本次比赛的一部分,既可以探索差异,也可以查看是否将原始数据集纳入训练会提高模型性能。

文件

  • data.csv:比赛数据集;您的目标是填补特征x_e_out(平衡质量)的缺失值。
  • sample_submission.csv:正确格式的示例提交文件。

评估指标

Submissions are scored on the root mean squared error. RMSE is defined as:

优胜方案

第一名

https://www.kaggle.com/competitions/playground-series-s3e15/discussion/414048

主要收获

  • 集成使用具有不同内部工作方式的模型,如基于树的方法、神经网络、线性模型和最近邻方法,即使它们在个体性能上较差
  • 利用领域知识来操作数据,用原始数据进行训练,但不用于验证。
  • 相信你的交叉验证(CV)分数。我试图不关注公共排行榜分数,而是专注于提高本地 CV 分数。我达到了一个极限,无法进一步提高。我知道要么是我漏掉了一些技巧(我在比赛结束后会很好奇学到这些技巧),要么是对于这个数据集的性能极限约为0.072。关于这一点:我有一个在私人排行榜上得分更高的提交,但我没有选择它,因为它的 CV 分数更差。

有效方法

  • 使用领域知识进行填充和范围剪切: @shalfey 在比赛结束后的讨论中提到了这一点。我意识到如果可以正确地填充“author”列,我们可以根据“author”值剪切其他特征的值,减少数据集中的噪音。这个方法最初由@arunklenin在评论线程中发布。
  • 对于“author”和“geometry”列的分类编码
  • 迭代填充: 使用树进行迭代地填充缺失值。感谢@arunklenin在这里分享这个方法。我很好奇你是如何调整这些参数的,因为它们效果非常好。
  • 使用 Optuna 调整模型参数。
  • 集成使用不同的模型。包括基于树的方法和神经网络等。尽管其中一些性能较差,但它们的工作方式为集成增添了多样性,正如@ambrosm在以前的比赛中多次指出的那样。最佳单一模型的CV为0.0730,但集成将其降低到0.726。
  • 适当的交叉验证,我使用了10折交叉验证,CV分数为Ensemble RMSE score 0.07265 ± 0.00202

未能成功的方法

  • 基于领域知识剪切目标变量值。
  • 对于“author”和“geometry”列的独热编码并没有真正帮助。它还增加了拟合时间,因为有更多的特征可用。
  • 添加PCA特征没有帮助。
  • 我尝试过使用自动编码器,但似乎没有什么帮助。可能没有正确地进行交叉验证。
  • 我还尝试将所有特征值剪切到+-3个标准差以减少异常值。这在CV中得分更高,但在私人排行榜上似乎过于乐观,约为0.069左右。的确,该提交的排行榜得分较差。
  • 开箱即用的填充方法效果较差。我认为基于树的方法效果最好,因为它几乎可以根据其他特征的值(如“author”和“geometry”等)制定“if-else”模式。

第二名

https://www.kaggle.com/competitions/playground-series-s3e15/discussion/413826

我的解决方案基于可视化分析结果观察,我的计划如下

步骤1:对比赛数据集进行简要的探索性数据分析(EDA),以初步了解数据。

1.1. 'D_h'
'D_e'
高度相关,且大部分情况下相同(影响了我的填充策略)。1.2. 存在类别不平衡,'tube' 几何图形是占比最多的类别(影响了模型选择)。1.3. 数据随机缺失,这可能是人为添加噪音的结果(影响了模型和填充策略的选择)。

步骤2:我决定只使用梯度提升模型,因为它可以很好地处理缺失值和类别不平衡。

在以前的填充比赛中,获胜的解决方案是基于深度学习的,但我认为由于数据集规模较小且存在大量缺失值,尝试深度学习不值得。我创建了几个基线模型,并使用统计方法填充缺失特征(将NaN值用每个特征按'author'分组后的均值填充)以检查其性能。

2.1. FLAML 单个 LGBM 模型给出了 CV 分数为 0.0733(使用 @paddykb 在 3.14 比赛中的 FLAML notebook,稍作修改,感谢这个出色的框架)。

2.2. 基于 Optuna 的基线模型也给出了 CV 分数约为 0.073(感谢 @tetsutani 的 model,我使用了该 notebook 中的部分代码)。

步骤3:基线模型的 CV 分数已经非常好,因此我决定不再花时间寻找更好的模型。

而是专注于改进填充技术和找到一些“窍门”,因为我知道这个数据是合成生成的。

3.1. 由于我已经看到数据集中添加了许多噪音,我决定将其与原始数据集进行比较。我之前在这篇帖子中分享了我的见解。

3.2. 在我发现一些特征总是一起出现且只属于单个作者时,我通过在原始数据集中查找唯一的特征对和三元组来填充竞赛数据。

3.3. 仍然存在一些缺失特征,所以我决定尝试不同的基于 MICE(多重插补法)的包,如 miceforestmissingpy 等。此外,@arunklenin 的一个出色的 notebook 中,他使用了基于 CatBoost 的自定义 MICE 算法实现,效果也非常好。

3.4. 我还尝试将填充的特征四舍五入到原始数据的最接近唯一值,但这使得 CV 分数变差。同时感谢 @alexdippolito 的这个帖子,他也探索了原始数据集的特征,这让我觉得我走在正确的道路上。也恭喜他获得第三名!

我从这个比赛中学到了什么?

  • 花更多时间进行探索性数据分析和了解数据。
  • 进行更多的实验,始终信任交叉验证(CV)结果。 始终依赖您的CV,将公共排行榜视为工具之一,但不要完全依赖它。同时,不要回避得分较低的笔记本,因为它们可能包含比排名靠前的笔记本更有用的信息。
  • 利用 Playground 数据集是合成的事实。 通过探索原始数据,您很可能会发现一些技巧,可以显著提高最终得分。
  • 不要害羞,作为初学者。 起初,我有些犹豫,因为我学习数据科学仅仅五个月,但事实证明,我获得最高分的机会与其他人一样大。此外,Kaggle 社区非常友好,总是乐于助人。

第三名

https://www.kaggle.com/competitions/playground-series-s3e15/discussion/414027

数据预处理

初始步骤涉及大量手动工作,浏览数据并寻找解决更容易的缺失值的模式。这填补了列 D_e、D_h 和 length 中的大多数值。以下是作者为 'Inasaka' 行编写的代码的一个小样本:

data.loc[(data['author'] == 'Inasaka') & ((data['D_h'] == 3.0) | (data['length'] == 100.0)) & (data['D_e'].isnull()), 'D_e'] = 3

data.loc[(data['author'] == 'Inasaka') & ((data['D_e'] == 3.0) | (data['length'] == 100.0)) & (data['D_h'].isnull()), 'D_h'] = 3

data.loc[(data['author'] == 'Inasaka') & ((data['D_e'] == 3.0) | (data['D_h'] == 3.0)) & (data['length'].isnull()), 'length'] = 100

接下来的预处理步骤是使用 K 最近邻 imputer 填充压力、质量通量和剩余的 D_e、D_h 和 length 中的缺失值。感谢 @validmodel 提供的帖子,其中列出了许多不同的缺失值填充技术。这最终让我选择了 sklearn 的 KNN imputer 来填充剩余的数值值。我尝试了不同的 n_neighbors 参数值,发现我的模型在 87 到 89 的范围内获得了最佳的 CV 分数。

缺失的分类列使用一些手动代码进行填充,如下所示:

data.loc[(data['author'] == 'Inasaka') & ((data['D_h'] == 3.0) | (data['length'] == 100.0)) & (data['D_e'].isnull()), 'D_e'] = 3

data.loc[(data['author'] == 'Inasaka') & ((data['D_e'] == 3.0) | (data['length'] == 100.0)) & (data['D_h'].isnull()), 'D_h'] = 3

data.loc[(data['author'] == 'Inasaka') & ((data['D_e'] == 3.0) | (data['D_h'] == 3.0)) & (data['length'].isnull()), 'length'] = 100

这样做效果相当不错,我得到了可靠的 CV 分数,但不是最强的公共 LB 分数(稍后会详细介绍)。

然而,在比赛结束前不久,@shalfey 发表了这篇出色的帖子。我将所有这些代码放在了我的预处理步骤前面。这导致了我的分数明显提高,如果没有这个帖子,我肯定不会获得如此高的排名。

模型构建和交叉验证

我首先构建了一个基本的未经调整的 XGBoost 模型,以获得基线的 CV 分数。当它的得分在约 0.07305 附近时,我感到非常惊讶。这个分数比公共 LB 的第一名得分(当时约为 0.0743)要好得多。这让我感到非常担忧 😬。

这个基本模型不仅会让我获得第一名,而且会让我远远超过第一名,几乎是不可能的。但我还是继续前进,对模型进行了调整,进行了一些测试预测,并提交了结果。公共分数达到了 0.07555。

CV 分数和公共 LB 分数之间存在差距的可能原因有两个:

  1. 我的 CV 在某个地方出现了问题(我强烈怀疑我的缺失值填充预处理策略导致了目标泄漏)
  2. 用于公共 LB 的 20% 数据包含了我的模型在某个异常部分上的表现不佳,但在整个测试集上的表现更接近我的 CV。

我相当肯定问题是第一种情况。我花了很多时间改变我的工作流程,以消除任何目标泄漏的可能性。然而,我的 CV 分数仍然在约 0.0732 左右。当我提交这些模型时,我的公共 LB 分数也要差得多。这些结果开始让我相信,第二种情况实际上是正确的。

基于此,我回到了最初的工作流程,即在交叉验证之前进行所有预处理和填充,而不是逐折进行。在这种情况下,存在轻微的目标泄漏(因为 KNN Imputer 使用了目标特征),但可以增加数据质量/输入特征的准确性,从而提高模型训练的质量。

如果我正在设置一个真实的交叉验证实验,正确的选择是逐折地进行所有填充,并在必要时收集更多数据以改善结果。但在这种情况下,明显没有收集更多的数据的选项。我受限于比赛/原始数据集,需要充分利用它们来最大程度地提高 KNN Imputer 步骤的准确性,即使这样做会导致微小的目标泄漏。

利用原始数据集在进行这些 playground 系列比赛时,一个独特的特

点是它们都使用从原始数据集生成的合成数据。这总是会引出一个问题:“我们该如何处理原始数据?”根据我参加的 playground 系列比赛,答案是你总是需要找到一种方法来利用它。

我必须感谢 @adaubas 在蓝莓产量比赛期间提供的帖子,真正让我思考原始数据集应该如何使用。我过去只是把它简单地视为额外的数据,然后立即将其连接到训练数据集。但我发现这并不是处理它的最佳方式。

这样做的问题在于,当进行 CV 时,将改变 OOF 验证数据的分布。合成数据似乎总是比原始数据噪声要大得多。@sergiosaharovskiy 的这篇帖子是对观察到的现象的很好的可视化。将原始数据包含在 OOF 验证数据中将为您提供比使用模型纯粹预测合成测试数据时可以期望的更好的 CV 分数。

我发现使用原始数据的最佳方法是将其与训练数据分开,然后将整个原始数据拼接回每个交叉验证的折叠中。以下是示例代码,其中 X_original 和 y_original 是整个原始数据集。

kf = KFold(n_splits=10, random_state=8, shuffle=True)

for train_idx, val_idx in kf.split(X_tr, y_tr):
    X_t, X_val = X_tr.iloc[train_idx], X_tr.iloc[val_idx]
    y_t, y_val = y_tr.iloc[train_idx], y_tr.iloc[val_idx]

    X_train = pd.concat([X_t, X_original], ignore_index=True)
    y_train = pd.concat([y_t, y_original], ignore_index=True)

    model = LGBMRegressor()

    model.fit(X_train, y_train, eval_set=[(X_val, y_val)])

    y_pred = model.predict(X_val)

    score = mean_squared_error(y_val, y_pred, squared=False)

模型和集成

最终,我调整了 4 个我满意的模型,想看看它们作为一个集成如何表现。

  • 模型 1:使用原始数据集的所有特征,除了 geometry 的 LightGBM 模型。
  • 模型 2:与模型 1 相同的 LightGBM 模型,但还添加了两个新特征 'adiabatic_surface_area' 和 'surface_diameter_ratio'。特别感谢 @tetsutani 和他的笔记本提供的特征思路。
  • 模型 3:与模型 2 相同的 LightGBM 模型,但还使用 PLSRegression 在特征 mass_flux、pressure 和 chf_exp 上添加了一个单一的特征/成分。再次感谢 @adaubas 的这篇帖子,让我了解到 PLS。
  • 模型 4:与模型 1 相同的特征的 XGBoost 模型。

结论

这个比赛进一步强化了我一个观念,那就是最重要的是要建立一个你信任的 CV 工作流程。让 CV 分数指导您的决策,不要过多依赖公共 LB 分数。

再次感谢社区中的每一位成员,他们热情好客并乐于分享他们的知识!我学到了很多!祝大家在未来的比赛中好运!

第五名

https://www.kaggle.com/competitions/playground-series-s3e15/discussion/413742

https://www.kaggle.com/code/iqbalsyahakbar/5-part-2-model-building?scriptVersionId=131500687

填充

通过数据分析可以发现每个author
只有一个geometry
的严格对应关系。Pandas Dataframe的groupby
方法发现了完全相同的事情。以下是我发现的大部分特征:

  1. 每个作者都有自己独特的几何形状。
  2. 对于一些作者,只有一个唯一的pressure [MPa]
  3. 对于一些作者,只有一对唯一的D_e [mm]
    D_h [mm]
  4. 对于一些作者,只有一个唯一的length [mm]
  5. 对于每一对chf_exp [MW/m2]
    length [mm]
    ,只有一个唯一的geometry
  6. 每个D_h [mm]
    都恰好有一个唯一的geometry
  7. 每个D_h [mm]
    都恰好有一个唯一的D_e [mm]

我的填充基本上是根据原始数据集中其他特征的值来查找缺失值。例如,为了填充D_e [mm]
,我必须使用竞赛数据集上的可用D_h [mm]
值,并用它在原始数据集上搜索D_e [mm]
的值。

现在,你们中的一些人可能已经知道,由于我们使用的是合成数据集,因此在特征之间创建一些关系会变得混乱,并在数据集中引入噪音。显然,这会使竞赛数据集与原始数据集不同。

特征工程

我一些特征工程的想法是基于圆柱体的。我受到了长度和直径特征的存在启发。我的想法如下:

  1. 加热直径和液压直径之间的差异
  2. 圆柱体表面积及其在加热和液压版本之间的差异
  3. 圆柱体体积及其在加热和液压版本之间的差异

还有一个其他的想法。它基于x_e_out [-]
没有任何度量单位,正如您从其特征名称中所看到的那样。这个想法是对pressure [MPa]
mass_flux [kg/m2-s]
chf_exp [MW/m2]
进行一些简单的数学运算,以去除它们的度量单位。

模型和集成

说实话,这没什么特别的,可能是我未能取得更高名次的原因。我使用不同的特征工程思路创建不同的模型,对其中一些模型使用不同的估算器。为了找到最佳权重,我使用Ridge回归,允许同时拟合拦截器和负系数。我还使用原始数据集来训练我的模型(当然不包括在我的验证中)。

最后,为了调整我的模型,我使用Optuna来进行梯度提升,如XGBoost和LightGBM,以及手动调整其他内容。就是这样,没有太多其他要解释的地方。

第九名

https://www.kaggle.com/competitions/playground-series-s3e15/discussion/413808

  1. 使用伪标签扩展训练数据: 使用前5个公开解决方案的集成来为缺失的目标创建伪标签。
  2. 使用Sklearn IterativeImputer和DecisionTreeRegressor进行特征工程: 由于训练数据中有许多缺失值,无论是在目标还是在特征中,Sklearn IterativeImputer与DecisionTreeRegressor可能是一个不错的选择,后者稍后可以与其他标准的缺失值处理方法集成在一起。
  3. 使用AutoML框架加快速度,特别是在回归问题中,它们提供了许多不同的模型,这对于最终的集成是有益的。

基于上述想法,我使用Auto Gluon框架训练了它们的混合,总共有5个解决方案,例如一个未经修改的训练流程,一个使用多次Sklearn IterativeImputer + DecisionTreeRegressor进行特征工程的流程,两阶段伪标签(首先在公开数据上,然后从训练过的AG模型上),以及将AG FTTransformer应用于模型。

然后,基于结果对这5个训练好的解决方案进行了加权集成。

 竞赛交流群 邀请函  #

△长按添加竞赛小助手

每天大模型、算法竞赛、干货资讯

与 37000+来自竞赛爱好者一起交流~

文章转载自Coggle数据科学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论