Kaggle竞赛S6E4:Predicting Irrigation Need 题解 Score:0.96907
1. 题目概述
2026年Kaggle Playground Series -Season 6 Episode 4
竞赛地址:https://www.kaggle.com/competitions/playground-series-s6e4/overview
目标:预测灌溉需求
评价:提交内容的评估基于预测类别与观察目标之间的平衡准确性
本文章代码已开源
github:https://github.com/Gxinglan/Kaggle-Predicting-Irrigation-Need
kaggle:https://www.kaggle.com/code/starxinglan/predicting-irrigation-need-2-3
1.1 提交要求
对于测试集中的每个目标,你必须预测一个类别标签(低、中、高)。文件应包含一个头部,格式如下:id,Irrigation_Need
| id | Irrigation_Need |
|---|---|
| 630000 | Low |
| 630001 | High |
| 630002 | Low |
| … | … |
1.2 训练集 train.csv
1.2.1 训练集数据结构
该数据集包含多维度的农业环境与作物生长特征。字段说明及部分样本示例:
| 字段名称 | 字段说明 | 示例数据 |
|---|---|---|
| id | 样本唯一标识 | 0, 1, 2 … |
| Soil_Type | 土壤类型 | Loamy, Clay, Sandy |
| Soil_pH | 土壤酸碱度 | 4.92, 7.08, 5.69 |
| Soil_Moisture | 土壤湿度 (%) | 32.58, 56.61, 27.71 |
| Organic_Carbon | 有机碳含量 | 1.01, 0.44, 0.81 |
| Electrical_Conductivity | 电导率 | 3.05, 2.00, 2.83 |
| Temperature_C | 温度 (°C) | 15.01, 22.92, 26.97 |
| Humidity | 湿度 (%) | 50.61, 67.86, 92.22 |
| Rainfall_mm | 降雨量 (mm) | 725.99, 985.66, 2201.70 |
| Sunlight_Hours | 日照时长 (小时) | 5.90, 6.98, 6.05 |
| Wind_Speed_kmh | 风速 (km/h) | 16.79, 3.39, 3.85 |
| Crop_Type | 作物类型 | Sugarcane, Wheat, Rice |
| Crop_Growth_Stage | 作物生长阶段 | Sowing, Vegetative, Reproductive |
| Season | 季节 | Zaid, Kharif, Rabi |
| Irrigation_Type | 灌溉类型 | Drip, Rainfed, Sprinkler |
| Water_Source | 水源 | Rainwater, River, Reservoir |
| Field_Area_hectare | 地块面积 (公顷) | 0.82, 5.27, 8.24 |
| Mulching_Used | 是否使用覆盖物 | Yes, No |
| Previous_Irrigation_mm | 上次灌溉量 (mm) | 112.16, 47.16, 110.38 |
| Region | 区域 | East, South, North |
| Irrigation_Need | 灌溉需求标签 (目标值) | Low, Medium, High |
1.2.2 部分样本数据实例
| id | Soil_Type | Soil_pH | Soil_Moisture | Organic_Carbon | Electrical_Conductivity | Temperature_C | Humidity | Rainfall_mm | Sunlight_Hours | Wind_Speed_kmh | Crop_Type | Crop_Growth_Stage | Season | Irrigation_Type | Water_Source | Field_Area_hectare | Mulching_Used | Previous_Irrigation_mm | Region | Irrigation_Need |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Loamy | 4.92 | 32.58 | 1.01 | 3.05 | 15.01 | 50.61 | 725.99 | 5.90 | 16.79 | Sugarcane | Sowing | Zaid | Drip | Rainwater | 0.82 | No | 112.16 | East | Low |
| 1 | Clay | 7.08 | 56.61 | 0.44 | 2.00 | 22.92 | 67.86 | 985.66 | 6.98 | 3.39 | Wheat | Vegetative | Kharif | Rainfed | River | 5.27 | Yes | 47.16 | South | Low |
| 2 | Clay | 5.69 | 27.71 | 0.81 | 2.83 | 26.97 | 92.22 | 2201.70 | 6.05 | 3.85 | Rice | Vegetative | Kharif | Sprinkler | Reservoir | 8.24 | Yes | 110.38 | North | Low |
| … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
1.3 测试集 test.csv
测试集特征结构与训练集基本一致,不含标签 Irrigation_Need。我们需要做的就是对Irrigation_Need进行预测。
1.3.1 部分样本数据实例
| id | Soil_Type | Soil_pH | Soil_Moisture | Organic_Carbon | Electrical_Conductivity | Temperature_C | Humidity | Rainfall_mm | Sunlight_Hours | Wind_Speed_kmh | Crop_Type | Crop_Growth_Stage | Season | Irrigation_Type | Water_Source | Field_Area_hectare | Mulching_Used | Previous_Irrigation_mm | Region |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 630000 | Silt | 6.36 | 26.19 | 0.59 | 2.81 | 17.83 | 30.24 | 1533.38 | 5.4 | 3 | Maize | Sowing | Rabi | Canal | River | 13.59 | Yes | 47.48 | West |
| 630001 | Clay | 5.87 | 9.88 | 1.18 | 3.26 | 21.18 | 78.07 | 576.05 | 7.22 | 15.88 | Cotton | Sowing | Rabi | Drip | Reservoir | 6.12 | Yes | 56.43 | South |
| 630002 | Sandy | 6.22 | 26.55 | 0.96 | 0.85 | 26.87 | 60.35 | 545.3 | 9.43 | 2.63 | Wheat | Sowing | Kharif | Sprinkler | Reservoir | 3.11 | Yes | 20 | East |
| … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … | … |
2. 解题代码讲解
本方案采用CatBoostClassifier模型,结合农业领域知识构建有效特征,使用7 折分层交叉验证保证训练稳定,通过类别权重处理样本不均衡问题,最终对多折模型的预测概率进行融合平均,得到稳健的预测结果并生成提交文件。
采用7折目前跑出来的结果是最好的,以下是在各折下跑的分数结果。
在5折时分数跑到了0.96805
在6折时分数跑到了0.96820
在7折时分数跑到了0.96907
在8折时分数跑到了0.96749
在10折时分数跑到了0.96728
2.1 CatBoost
CatBoost是俄罗斯的搜索巨头Yandex在2017年开源的机器学习库,是Boosting族算法的一种。CatBoost和XGBoost、LightGBM并称为GBDT的三大主流神器,都是在GBDT算法框架下的一种改进实现。其中CatBoostClassifier 是CatBoost库里专门做分类任务的模型。
其有三个主要特点:
- 自动处理类别特征:无需繁琐的特征编码,直接原始数据
- 有序目标统计:有效防止目标泄露(Target Leakage)
- 对称决策树:训练更快更不容易拟合
因此,CatBoost 尤其适用于包含大量类别特征、数值与类别特征存在复杂交互、需要快速搭建高质量基线模型的表格数据场景。
2.1.1 有序目标统计:比 One-Hot 更智能的类别特征处理策略
在类别型特征的处理中,传统方法存在固有局限:独热编码(One-Hot Encoding)易引发维度灾难,导致特征空间高维稀疏;标签编码(Label Encoding)则会人为引入虚假的顺序关系,破坏特征的语义独立性。CatBoost 通过有序目标统计(Ordered Target Statistics)机制,解决了这一矛盾。
核心原理
有序目标统计的核心逻辑基于时序化的目标均值编码,具体流程如下:
- 样本随机排序:训练前对全体样本进行随机重排,构建时序化的样本序列。
- 历史信息编码:对于第 i i i 个样本的类别特征值,仅使用前 i − 1 i-1 i−1 个样本中相同类别的目标值均值作为编码结果。
- 先验平滑处理:引入先验概率对编码结果进行平滑,缓解小样本类别统计不稳定的问题。
其优势在于优势
- 避免了未来信息的泄漏
- 保留了类别特征的统计特性
2.2.2 对称树: 决策树中的标准化结构
与 XGBoost 等传统框架采用的非对称决策树不同,CatBoost 使用对称树(Oblivious Trees) 结构。该结构的核心特点是,树的每一层所有节点均使用相同的特征与阈值进行分裂,结构规整且统一。
这种结构有以下优点:
- 训练速度快:可并行计算所有叶节点的分裂
- 内存效率高:只需要存储每层的分裂特征和阈值
- 正则化结果好:限制了模型的复杂度
但对称树也有其局限性,当特征交互非常复杂时,可能不如传统决策树灵活。
CatBoost的主要算法原理可以参考以下两篇论文:
- Anna Veronika Dorogush, Andrey Gulin, Gleb Gusev, Nikita Kazeev, Liudmila Ostroumova Prokhorenkova, Aleksandr Vorobev “Fighting biases with dynamic boosting”. arXiv:1706.09516, 2017
- Anna Veronika Dorogush, Vasily Ershov, Andrey Gulin “CatBoost: gradient boosting with categorical features support”. Workshop on ML Systems at NIPS 2017
2.2 代码
2.2.1 导入库
import os
import pandas as pd
import numpy as np
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import f1_score, classification_report
from sklearn.utils.class_weight import compute_class_weight
from catboost import CatBoostClassifier
import os:导入操作系统工具,用于文件路径管理与文件读写。import pandas as pd:数据处理核心库,用于读取 CSV、表格数据操作。import numpy as np:数值计算库,用于数组运算、概率融合等。StratifiedKFold:分层 K 折交叉验证,保证每一折数据的类别分布与原数据一致。f1_score, classification_report:模型评估指标,用于计算 F1 分数与输出分类报告。compute_class_weight:计算类别平衡权重,解决样本分布不均衡问题。CatBoostClassifier:CatBoost 分类模型。
2.2.2 设置文件路径与运行模式
# 配置路径
TRAIN_PATH = "./train.csv"
TEST_PATH = "./test.csv"
SUBMISSION_OUTPUT_PATH = "./submission_final.csv"
# 训练模式:GPU or CPU
TRAINING_MODE = "GPU"
TRAIN_PATH:训练集文件路径,指定代码读取训练数据的位置。TEST_PATH:测试集文件路径。SUBMISSION_OUTPUT_PATH:最终提交文件保存路径。TRAINING_MODE:训练模式,GPU或者CPU。
2.2.3 读取数据集与测试集数据
# 读取数据
train = pd.read_csv(TRAIN_PATH)
test = pd.read_csv(TEST_PATH)
# 保存测试集 ID,用于最后提交
submission = test[["id"]].copy()
pd.read_csv(TRAIN_PATH):从指定路径读取训练集数据,生成 DataFrame 数据结构。pd.read_csv(TEST_PATH):读取测试集数据,用于后续预测。submission = test[["id"]].copy():单独复制测试集的 id 列,用于最终生成提交文件。
2.2.4 标签处理
# 标签映射
label_map = {"Low": 0, "Medium": 1, "High": 2}
train["Irrigation_Need"] = train["Irrigation_Need"].map(label_map)
# 划分特征和标签
X = train.drop(["id", "Irrigation_Need"], axis=1)
y = train["Irrigation_Need"]
X_test = test.drop(["id"], axis=1)
label_map:将标签文本(Low/Medium/High)映射为模型可处理的数字(0/1/2)。map():批量替换训练集标签为数值形式。X:训练集特征,剔除id与标签列。y:训练集标签,即需要预测的灌溉需求等级。X_test:测试集特征,仅剔除id列。
2.2.5 特征工程
# 构造关键特征
def create_features(df):
# 1. 参考作物蒸散量
df["ET0"] = df["Temperature_C"] * df["Wind_Speed_kmh"] * df["Sunlight_Hours"] / df["Humidity"]
# 2. 水平衡:降水 + 上次灌溉 - 蒸发
df["Water_Balance"] = df["Rainfall_mm"] + df["Previous_Irrigation_mm"] - df["ET0"]
# 3. 水分胁迫指数
df["Moisture_Stress"] = df["Temperature_C"] * (100 - df["Humidity"]) / df["Soil_Moisture"]
# 4. 组合特征
df["Crop_Growth"] = df["Crop_Type"] + "_" + df["Crop_Growth_Stage"]
df["Region_Season"] = df["Region"] + "_" + df["Season"]
return df
# 对训练集和测试集都应用特征工程
X = create_features(X)
X_test = create_features(X_test)
create_features(df):自定义特征工程函数,用于批量构造新特征。df["ET0"]:构造蒸散量特征,反映水分蒸发强度。
公式:温度 × 风速 × 日照时长 / 湿度df["Water_Balance"]:构造水平衡特征,衡量土壤水分盈亏状态。
公式:降雨量 + 上次灌溉量 − 蒸散量df["Moisture_Stress"]:构造水分胁迫指数,表征作物缺水压力。
公式:温度 × (100−湿度) / 土壤湿度df["Crop_Growth"]:作物类型与生长阶段交叉组合特征。df["Region_Season"]:地区与季节交叉组合特征。X = create_features(X):对训练集执行特征工程。X_test = create_features(X_test):对测试集执行相同特征工程。
2.2.5 识别并处理类别特征
# 类别型特征列名
cat_features = [
"Soil_Type", "Crop_Type", "Crop_Growth_Stage", "Season",
"Irrigation_Type", "Water_Source", "Mulching_Used", "Region",
"Crop_Growth", "Region_Season"
]
# 确保类别特征是字符串格式
for col in cat_features:
X[col] = X[col].astype(str)
X_test[col] = X_test[col].astype(str)
cat_features:定义所有类别型特征列表,供 CatBoost 自动识别处理。for col in cat_features:遍历所有类别特征,统一转换数据类型。X[col] = X[col].astype(str):将训练集类别特征转为字符串格式。X_test[col] = X_test[col].astype(str):将测试集类别特征转为字符串格式。
2.2.7 计算类别权重
# 计算类别权重
weights = compute_class_weight(
class_weight="balanced", classes=np.unique(y), y=y
)
class_weights = dict(zip(np.unique(y), weights))
compute_class_weight():根据样本分布自动计算类别平衡权重。class_weight="balanced":启用平衡模式,自动修正样本分布不均问题。np.unique(y):获取数据集中所有不重复的标签类别。class_weights:存储类别与对应权重的字典,供模型训练时使用。
2.2.8 设置7折分层交叉验证
# 7折交叉验证
skf = StratifiedKFold(n_splits=7, shuffle=True, random_state=42)
test_pred_probs = []
StratifiedKFold:分层 K 折交叉验证,保持每折数据类别分布一致。n_splits=8:将数据集划分为 7 份,7折交叉验证。shuffle=True:训练前打乱数据顺序,提升模型泛化能力。random_state=42:固定随机种子,保证实验可复现。test_pred_probs:空列表,用于存储每一折模型的预测概率。
2.2.9 训练模型
for fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):
print(f"\n========== Fold {fold + 1} ==========")
# 划分训练集与验证集
X_train, X_val = X.iloc[train_idx], X.iloc[val_idx]
y_train, y_val = y.iloc[train_idx], y.iloc[val_idx]
# 定义 CatBoost 模型
model = CatBoostClassifier(
iterations=1000,
learning_rate=0.1,
depth=6,
eval_metric="TotalF1",
early_stopping_rounds=200,
class_weights=class_weights,
task_type=TRAINING_MODE,
random_state=42,
verbose=100
)
# 训练模型
model.fit(
X_train, y_train,
eval_set=(X_val, y_val),
cat_features=cat_features,
use_best_model=True
)
# 验证集评估
val_pred = model.predict(X_val)
f1 = f1_score(y_val, val_pred, average="macro")
print(f"Fold {fold+1} F1 Score: {f1:.4f}")
print(classification_report(y_val, val_pred))
# 保存测试集预测概率
test_pred_probs.append(model.predict_proba(X_test))
for fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):按折循环,拆分训练集与验证集索引。X_train, X_val:按索引划分训练集与验证集特征。y_train, y_val:按索引划分训练集与验证集标签。CatBoostClassifier():初始化 CatBoost 分类模型。iterations=1000:最大迭代次数(树的数量)。learning_rate=0.1:模型学习率。depth=6:决策树最大深度。eval_metric="TotalF1":以 F1 分数作为评估指标。early_stopping_rounds=200:早停策略,防止过拟合。class_weights=class_weights:传入类别平衡权重。task_type=TRAINING_MODE:指定使用 CPU / GPU 训练。random_state=42:固定随机种子,保证可复现。verbose=100:每 100 轮输出一次训练日志。model.fit():在训练集上训练,在验证集上验证。cat_features=cat_features:指定类别特征,让模型自动处理。use_best_model=True:使用最优迭代轮数的模型。model.predict():对验证集进行预测。f1_score():计算验证集宏观 F1 分数。classification_report():输出完整分类评估报告。model.predict_proba():对测试集预测概率。test_pred_probs.append():将每折预测概率存入列表。
2.2.10 多模型预测结果融合
# 对 7 个模型的预测概率求平均
avg_pred_probs = np.mean(test_pred_probs, axis=0)
# 取概率最大的类别作为最终预测
predictions = np.argmax(avg_pred_probs, axis=1)
np.mean(test_pred_probs, axis=0):对8折模型的预测概率按列求平均,提升结果稳定性。np.argmax(avg_pred_probs, axis=1):取每行概率最大的值对应的类别,生成最终预测标签。avg_pred_probs:存储多模型融合后的平均预测概率。predictions:存储最终的类别预测结果。
2.2.11 生成提交文件
# 把数字转回标签
label_map_inv = {0: "Low", 1: "Medium", 2: "High"}
submission["Irrigation_Need"] = predictions
submission["Irrigation_Need"] = submission["Irrigation_Need"].map(label_map_inv)
# 保存文件
submission.to_csv(SUBMISSION_OUTPUT_PATH, index=False)
print(f"\n提交文件已保存至:{SUBMISSION_OUTPUT_PATH}")
label_map_inv:将预测的数字标签映射回原始文本标签。submission["Irrigation_Need"]:将预测结果存入提交文件。map(label_map_inv):批量转换数字为文本标签。submission.to_csv():将结果保存为CSV格式提交文件。index=False:不保存行索引,符合竞赛提交格式要求。print():输出文件保存路径,方便查看结果。
注:水平有限,若存在错误或可优化之处,欢迎各位批评指正。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)