kaggle帕金森病进展预测大赛金牌方案分享

文章介绍了帕金森病的挑战和其对社会的影响,以及一个旨在通过数据科学预测疾病进展的竞赛。参赛者需预测MDS-UPDRS评分,利用时间序列数据和提供的API进行建模。优胜方案采用了LGB和NN模型的组合,重点在于数据预处理和特征工程。

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

赛题背景

帕金森病 (PD) 是一种致残的脑部疾病,会影响运动、认知、睡眠和其他正常功能。不幸的是,目前没有治愈的方法 - 并且疾病会随着时间的推移而恶化。据估计,到2037年,美国将有1万人患有帕金森病,经济成本接近6亿美元。研究表明,蛋白质或肽异常在这种疾病的发作和恶化中起着关键作用。在数据科学的帮助下,更好地了解这一点可以为开发新的药物治疗以减缓进展或治愈帕金森病提供重要线索。

竞赛主办方加速药物伙伴关系®帕金森病(AMP®PD)是政府,行业和非营利组织之间的公私合作伙伴关系,通过美国国立卫生研究院基金会(FNIH)进行管理。该伙伴关系创建了AMP PD知识平台,其中包括帕金森病患者的深层分子表征和纵向临床分析,目的是识别和验证帕金森病的诊断,预后和/或疾病进展生物标志物。

您的工作可以帮助寻找治疗帕金森病的方法,这将减轻这种疾病患者的大量痛苦和医疗费用。

赛题任务

本次竞赛的目标是预测MDS-UPDR评分,该评分衡量帕金森病患者的进展。运动障碍协会赞助的统一帕金森病评定量表(MDS-UPDRS)修订版是对与帕金森病相关的运动和非运动症状的全面评估。

参赛者将开发一个模型,该模型根据帕金森病受试者与正常年龄匹配的对照受试者随时间推移的蛋白质和肽水平数据进行训练。

数据描述

这是一个时间序列代码竞赛:参赛者将接收测试集数据并使用Kaggle的时间序列API进行预测。

  • train_peptides.csv
    • visit_id

    • visit_month

    • patient_id

    • UniProt

    • Peptide

    • PeptideAbundance

  • train_proteins.csv
    • visit_id

    • visit_month

    • patient_id

    • UniProt

    • NPX

  • train_clinical_data.csv
    • visit_id

    • visit_month

    • patient_id

    • updrs_[1-4]

    • upd23b_clinical_state_on_medication

  • supplemental_clinical_data.csv

  • example_test_files/

  • amp_pd_peptide/

  • public_timeseries_testing_util.py

评估标准

提交的评估标准是预测值和实际值之间的SMAPE。当实际值和预测值都为0时,我们定义SMAPE = 0。对于每个采集蛋白质/肽样本的患者访问,参赛者需要估计他们在该次访问中的UPDRS得分,并预测其6、12和24个月后任何可能出现的访问得分。最终未进行任何访问的预测将被忽略。

参赛者必须使用提供的python 时间序列 API 提交此竞赛,以确保模型不会及时向前查看时间。若要使用 API,请按照 Kaggle 笔记本中的以下模板进行操作:

import amp_pd_peptide
env = amp_pd_peptide.make_env()   # initialize the environment
iter_test = env.iter_test()    # an iterator which loops over the test files
for (test, test_peptides, test_proteins, sample_submission) in iter_test:
    sample_prediction_df['rating'] = np.arange(len(sample_prediction))  # make your predictions here
    env.predict(sample_prediction_df)   # register your predictions

优胜方案

第一名

https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/discussion/411505

我们的最终解决方案是两个模型的简单平均值:LGB 和 NN。两个模型都基于相同的特征进行了训练(+NN的缩放/二值化):

  • 访问月

  • 预测范围

  • 目标预测月

  • 指示就诊期间是否采血

  • 补充数据集指标

  • 指标患者是否在第 6、18 和 48 个月就诊

  • 以前的“非年度”访问次数(第 6 次或第 18 次)

  • 目标索引(我们将数据集透视为具有单个目标列)

核心代码:

import numpy as np
import pandas as pd
from sklearn.model_selection import KFold

def load_data(base_path = "data"):
    proteins = pd.read_csv(f"{base_path}/train_proteins.csv")
    peptides = pd.read_csv(f"{base_path}/train_peptides.csv")
    clinical = pd.read_csv(f"{base_path}/train_clinical_data.csv")
    supplement = pd.read_csv(f"{base_path}/supplemental_clinical_data.csv")
    return proteins, peptides, clinical, supplement

proteins, peptides, clinical, supplement = load_data("../input/amp-parkinsons-disease-progression-prediction")
supplement.loc[supplement["visit_month"] == 5, "visit_month"] = 6

def smape1p_ind(A, F):
    val = 200 * np.abs(F - A) / (np.abs(A+1) + np.abs(F+1))
    return val

def smape1p(A, F):
    return smape1p_ind(A, F).mean()

def max_dif(val, lst):
    lst0 = [x for x in lst if x < val]
    if len(lst0) == 0:
        return -1
    return val - max(lst0)

def count_prev_visits(val, lst):
    lst0 = [x for x in lst if x < val]
    return len(lst0)

class DataPrep:
    def __init__(self, target_horizons=[0, 6, 12, 24], test_vmonths = [0, 6, 12, 18, 24, 36, 48, 60, 72, 84]):
        self.target_horizons = target_horizons
        self.test_vmonths = test_vmonths

    def fit(self, proteins_df, peptides_df, clinical_df):
        pass

    def fe(self, sample, proteins_df, peptides_df, clinical_df):
        for v_month in [0, 6, 12, 18, 24, 36, 48, 60, 72, 84]:
            p = list(clinical_df[clinical_df["visit_month"] == v_month]["patient_id"].unique())
            sample[f"visit_{v_month}m"] = sample.apply(lambda x: (x["patient_id"] in p) and (x["visit_month"] >= v_month), axis=1).astype(int)

            p = list(proteins_df[proteins_df["visit_month"] == v_month]["patient_id"].unique())
            sample[f"btest_{v_month}m"] = sample.apply(lambda x: (x["patient_id"] in p) and (x["visit_month"] >= v_month), axis=1).astype(int)

            sample[f"t_month_eq_{v_month}"] = (sample["target_month"] == v_month).astype(int)
            sample[f"v_month_eq_{v_month}"] = (sample["visit_month"] == v_month).astype(int)

        for hor in self.target_horizons:
            sample[f"hor_eq_{hor}"] = (sample["horizon"] == hor).astype(int)

        sample["horizon_scaled"] = sample["horizon"] / 24.0

        blood_samples = proteins_df["visit_id"].unique()
        sample["blood_taken"] = sample.apply(lambda x: x["visit_id"] in blood_samples, axis=1).astype(int)
        
        all_visits = clinical_df.groupby("patient_id")["visit_month"].apply(lambda x: list(set(x))).to_dict()
        all_non12_visits = sample.apply(lambda x: [xx for xx in all_visits.get(x["patient_id"], []) if xx <= x["visit_month"] and xx%12 != 0], axis=1)
        sample["count_non12_visits"] = all_non12_visits.apply(lambda x: len(x)) 

        return sample

    def transform_train(self, proteins_df, peptides_df, clinical_df):
        sample = clinical_df.rename({"visit_month":"target_month", "visit_id":"visit_id_target"}, axis=1).\
            merge(clinical_df[["patient_id", "visit_month", "visit_id"]], how="left", on="patient_id")
        sample["horizon"] = sample["target_month"] - sample["visit_month"]
        sample = sample[sample["horizon"].isin(self.target_horizons)]
        sample = sample[sample["visit_month"].isin(self.test_vmonths)]

        # Features
        sample = self.fe(sample,
            proteins_df[proteins_df["visit_month"].isin(self.test_vmonths)],
            peptides_df[peptides_df["visit_month"].isin(self.test_vmonths)],
            clinical_df[clinical_df["visit_month"].isin(self.test_vmonths)])

        # Targets reshape
        res = []
        for tgt_i in np.arange(1, 5):
            delta_df = sample.copy()
            if f"updrs_{tgt_i}" in delta_df.columns:
                delta_df["target"] = delta_df[f"updrs_{tgt_i}"]
                delta_df["target_norm"] = delta_df["target"] / 100
            delta_df["target_i"] = tgt_i
            res.append(delta_df)

        sample = pd.concat(res, axis=0).reset_index(drop=True)
        if f"updrs_1" in sample.columns:
            sample = sample.drop(["updrs_1", "updrs_2", "updrs_3", "updrs_4"], axis=1)
        
        for tgt_i in np.arange(1, 5):
            sample[f"target_n_{tgt_i}"] = (sample["target_i"] == tgt_i).astype(int)

        return sample
    
    def transform_test(self, proteins_df, peptides_df, test_df, sub_df):
        sub = sub_df.copy()
        sub["patient_id"] = sub["prediction_id"].apply(lambda x: int(x.split("_")[0]))
        sub["visit_month"] = sub["prediction_id"].apply(lambda x: int(x.split("_")[1]))
        sub["visit_id"] = sub.apply(lambda x: str(x["patient_id"]) + "_" + str(x["visit_month"]), axis=1)

        sample = sub[["patient_id", "visit_month", "visit_id", "prediction_id"]]

        sample["horizon"] = sample["prediction_id"].apply(lambda x: int(x.split("_")[5]))
        sample["target_i"] = sample["prediction_id"].apply(lambda x: int(x.split("_")[3]))
        sample["visit_month"] = sample["visit_month"]
        sample["target_month"] = sample["visit_month"] + sample["horizon"]
        del sample["prediction_id"]

        # Features
        sample = self.fe(sample, proteins_df, peptides_df, test_df)

        for tgt_i in np.arange(1, 5):
            sample[f"target_n_{tgt_i}"] = (sample["target_i"] == tgt_i).astype(int)

        return sample

dp3 = DataPrep()
dp3.fit(proteins, peptides, clinical)

sample3 = dp3.transform_train(proteins, peptides, clinical)
sample3 = sample3[~sample3["target"].isnull()]
sample3["is_suppl"] = 0

sup_sample3 = dp3.transform_train(proteins, peptides, supplement)
sup_sample3 = sup_sample3[~sup_sample3["target"].isnull()]
sup_sample3["is_suppl"] = 1

print(sample3.shape)
print(sup_sample3.shape)

第四名: https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/discussion/411398

第五名: https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/discussion/411388

关注下方【学姐带你玩AI】🚀🚀🚀

回复“比赛”领取190+场比赛top方案合集

码字不易,欢迎大家点赞评论收藏!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值