【Kaggle】练习赛《洪水数据集的回归预测》(下)

文章讲述了如何通过针对特征相似且相关性低的洪水数据集,采用深度学习的MLP模型并结合统计量特征工程,实现R2分数从0.846提升至0.86887的过程,强调了改变传统特征选择方法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

上篇《洪水数据集的回归预测》(上) 介绍了该数据集非常特殊之处,各特征都非常类似,没有特别之处,各特征之间的相关系数几乎为零。同时,各类模型不敏感,最理想的模型居然是线性回归,决定系数 R 2 R^2 R2,也只有 0.846。对这样的一个问题,我们如何突破呢?

方向一

既然线性模型效果相对于其他模型算是较好的,因此我们选择深度学习的MLP【多层感知器(multilayer Perceptron)】模型进行尝试,核心代码如下,

数据归一化

sc = preprocessing.StandardScaler()
X_scaled=sc.fit_transform(X) 
X_valid_scaled = sc.transform(X_valid)
test_scaled = sc.transform(test)
建模
model = Sequential() 
model.add(Dense(64, kernel_initializer = 'normal', activation = 'relu',
input_shape = (20,))) 
model.add(Dense(64, activation = 'relu'))
model.add(Dense(32, activation = 'relu'))
model.add(Dense(1))

第一个版本,中间层只有 64 一层

编译
model.compile(
   loss = 'mse', 
   optimizer = RMSprop(learning_rate=0.0005),  
   metrics =  ['mean_absolute_error']
)

这里选择 RMSprop 做为优化器,我尝试过用 Adam 效果差不多,同样,这里的学习率也可以做适当的调整。

训练
history = model.fit(
   X_scaled, y,    
   batch_size=128, 
   epochs = 500, 
   verbose = 1, 
   validation_split = 0.2, 
   callbacks = [EarlyStopping(monitor = 'val_loss', patience = 20)]
)

6988/6988 ━━━━━━━━━━━━━━━━━━━━ 13s 2ms/step - loss: 3.5157e-04 - mean_absolute_error: 0.0147 - val_loss: 3.5295e-04 - val_mean_absolute_error: 0.0146
Epoch 147/500
6988/6988 ━━━━━━━━━━━━━━━━━━━━ 13s 2ms/step - loss: 3.5114e-04 - mean_absolute_error: 0.0147 - val_loss: 3.6086e-04 - val_mean_absolute_error: 0.0145

第一版本,训练数据和验证数据分别 用train_test_split方式来进行训练
采用早停的方式来终止训练,这里共训练了147次,MSE 可以达到0.0145~0.0146之前

LOSS 结果
plt.plot(history.epoch,history.history.get('loss'),label="loss")
plt.xlabel("epoch")
plt.ylabel("MSE")
plt.legend()

在这里插入图片描述

查看验证结果
y_valid_pred = model.predict(X_valid_scaled)
r2_score(y_valid,y_valid_pred)

0.8628182472445698

0.8628,这个结果大大的超过了预期,第一个版本成绩为0.859,因此就选用了这个标题了,现在所展示的是第二个版本,具体详见 完整代码

以下是我当天提交结果

在这里插入图片描述

正当以为找到方案一,调整模型层数和相关参数提升模型效果时,很快发现又出称瓶颈(0.8645),不得不需要找到另外的突破的方式。

方案二

在上篇留了一个坑 ,也在总结 写到"如果直接用上述的数据建模的话, R 2 R^2 R2 的上限不太可能会突破0.85",尽管方案一突破了0.85 ,来到了0.86 这个区别,难道不能上0.87 那个区间吗。因此,我们突破常规思路,必须从数据集入手,有效的进行特征工具(FE),提升这些特征的有效性。

上文提到那些特征没有特色,具体普遍性,而机器学习在寻找特征的基本思想就是找出与别人不一校样的东西,如果一组数据没有波动,也不能称之为特征,因此,需要我们找出不一样的波动的东西,顺着这个思路,我们把以上原有特征的统计量给找出来,看看能发现什么。

选择统计量分析
# 求出相关的统计量,并删除原特征
def cleaning(dataset):
    features = dataset.columns.tolist()
    dataset['mean_features'] = 0.1*dataset[features].mean(axis=1)
    dataset['std_features'] = dataset[features].std(axis=1)
    dataset['max_features'] = dataset[features].max(axis=1)
    dataset['min_features'] = dataset[features].min(axis=1)
    dataset['median_features'] = 0.1*dataset[features].median(axis=1)
    # just keep the descriptive statistics
    dataset = dataset.drop(features, axis=1)

    return dataset
# 将原始数据和训练数据合并
dataset = pd.concat([original_data, train_data.drop('id', axis=1)], ignore_index=True)
X = dataset
X = X.drop(["FloodProbability"], axis=1)
X = cleaning(X)
y = dataset["FloodProbability"]
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats

# Plot scatter plots and regression lines for each feature in separate plots
for i, col in enumerate(X.columns):
    plt.figure(figsize=(6, 4))  # Create a new figure for each feature
    
    # Scatter plot and regression line
    sns.regplot(x=X[col], y=y, color='darkturquoise', 
                line_kws={'color': 'red'}, 
                scatter_kws={'alpha': 0.5})  # Set alpha for dot transparency
    
    # Calculate linear regression
    slope, intercept, r_value, p_value, std_err = stats.linregress(X[col], y)
    
    # Add title including the regression coefficients
    plt.title(f'{col} vs Target\nSlope: {slope:.2f}, Intercept: {intercept:.2f}')
    
    # Setting labels
    plt.xlabel(col)
    plt.ylabel('Target')
    
    plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们惊奇的发现,这些统计量与目标值【FloodProbability】居有具较强的相关性。
以此为起点,我们以上述统计量为特征,进行建模分析。
以下没有优化的结果如下

模型原始特征 R 2 R^2 R2统计量特征的 R 2 R^2 R2
LinearRegression0.8454600.84561
Lasso-5.51093-5.51093
Ridge0.8454600.84561
ElasticNet-5.51093-5.51093
SVR0.696670.78454
RandomForestRegressor0.653940.86045
XGBRegressor0.809420.869125
LGBMRegressor0.7671980.869094
CatBoostRegressor0.846690.869264
DL-MLP0.8628180.865859

以上表数据均为验证集的结果,未进行提交的成绩。

为了取得更好的成绩,我们将最好的三个模型进行融合。

xgb_pred = xgb.predict(test_t)
lgb_pred = lgb.predict(test_t)
cat_pred = cat.predict(test_t)
sample['FloodProbability'] = (xgb_pred+lgb_pred+cat_pred)/3
sample.to_csv("submit_melt.csv",index=None)

详见 notebook

最终,提交到竞赛中得到 0.86887的成绩,截止发稿,最好成绩为0.86932。
在这里插入图片描述

到这里暂告一段落,要想继续提升我们的成绩,还是有一定的空间,有几个方向供小伙伴参考

  • 上述的三个模型都是采用默认参数的方式,都可以进行 optuna 进行优化,参照我的几篇文章,如《肥胖风险的多类别预测》的 Optuna 进行微调部分。
  • 在融合方式中可以用不同权重进行优化。
  • 模型训练时可以用5折交叉验证来提升模型的泛化能力。

总结

  1. 写这篇文章的初衷,是为了一种思维的突破,改变原先常规的特征基础,选用统计量作为特征,这是我在以往所没有碰到过的,基于这一点,拿来分享给大家。
  2. 这种方法其实是有条件的,并非所有的题目都可以这样,只有当这些特征具有以下特点是,如所有特征具有共同的特性,并其相关性为零,特征量不太少,用一般的树形模型没法提升时。
  3. 每个数据集基于特征都有一个理论上限,如果已接近这个天花板时,就需要改变原先的特征,像本题,是一种完全改变的方式,除此之外,有扩展,PCA等方式。
    以上这些观点是我自己的感受和体会,并非一定正确,如有不想法和建议,欢迎评论。
### 参与或了解Kaggle上的洪水预测竞赛 #### 数据集概述 在Kaggle平台上,洪水预测相关的数据集通常包含了丰富的地理空间信息和时间序列特征。这些数据集可能来自不同的传感器网络、卫星影像以及历史记录。具体来说,这类数据集会包含河流流量、降雨量、土壤湿度等多种因素的数据[^1]。 对于想要参与此类项目的人员而言,理解如何获取并处理这些多源异构的数据至关重要。参赛者可以从公开渠道下载所需资料,并利用Python等编程语言来清洗预处理原始文件以便后续建模分析。 #### 解决方案框架 ##### 特征工程 为了提高模型性能,在构建预测算法之前需要进行充分的特征提取工作。这一步骤涉及到了解影响洪涝灾害发生的自然条件和社会经济背景等方面的知识。例如: - **降水累积**:计算一段时间内的总降水量作为输入变量之一; - **地形地貌属性**:考虑海拔高度差等因素对水流路径的影响; - **土地覆盖类型分布情况**:不同植被覆盖率下的水分蒸发速率差异会对径流形成过程造成显著改变; 以上提到的各项指标都可以通过对已有栅格图层执行相应的GIS操作获得。 ##### 模型选择与训练 针对本问题可以采用监督学习方法来进行回归任务求解。考虑到时空关联特性较强的特点,推荐使用LSTM(Long Short-Term Memory)神经网络架构或其他适合处理序列模式识别的任务专用结构如Transformer变体形式。此外还可以尝试集成传统统计物理模型(比如托马斯流域汇流方程)与现代深度学习技术相结合的方式以期达到更好的效果评估标准。 当涉及到实际编码实现部分时,则建议参考如下代码片段展示基于PyTorch框架搭建简单版本循环单元实例的方法: ```python import torch.nn as nn class FloodPredictor(nn.Module): def __init__(self, input_size=784, hidden_layer_size=100, output_size=1): super().__init__() self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_layer_size, batch_first=True) self.linear = nn.Linear(hidden_layer_size, output_size) def forward(self, x): lstm_out, _ = self.lstm(x.unsqueeze(-1)) predictions = self.linear(lstm_out[:, -1]) return predictions.squeeze() ``` 该段程序定义了一个继承自`nn.Module`类的新对象——FloodPredictor,其中封装了两层主要组件:一是负责捕捉长期依赖关系的记忆模块lstm;二是用来映射隐藏状态至最终输出维度线性变换linear。整个流程遵循张量流动方向依次完成初始化设定、正向传播运算直至返回预期结果为止。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值