aboutsummaryrefslogtreecommitdiffstats
path: root/.agents/skills/kaggle-learner/references/knowledge/tabular/amp-parkinsons-2021.md
blob: 82b4f3b1cad92561e0e67f5621a7a80cd01494ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
# AMP®-Parkinson's Disease Progression Prediction (2023)

## Competition Brief

**竞赛基本信息**
- **主办方**: AMP (Accelerating Medicines Partnership)
- **时间**: 2023年
- **类型**: 表格数据/医疗预测
- **数据规模**: 小样本数据集
- **评价目标**: SMAPE (Symmetric Mean Absolute Percentage Error)

**任务描述**
预测帕金森病患者的疾病进展情况。使用蛋白质和肽段数据(通过质谱测量脑脊液样本)来预测患者未来的 MDS-UPDRS 评分。

**数据特点**
- **蛋白质数据**: 227个蛋白质特征
- **肽段数据**: 来自多个质谱实验
- **时间序列**: 每个患者有多次访问记录
- **样本量**: 相对较小(小样本竞赛)
- **目标变量**: MDS-UPDRS 评分的进展

**评价指标**
SMAPE (Symmetric Mean Absolute Percentage Error)
- 对称性平均绝对百分比误差
- 范围 [0, 200],越小越好
- 对异常值相对鲁棒

---

## Top Solutions Analysis

### 1st Place - Connecting Dotts (Dmitry Gordeev et al.)

**核心策略**
- **模型组合**: LightGBM + Neural Network 的简单平均
- **特征工程**: 精心设计的蛋白质和肽段聚合特征
- **数据处理**: 针对神经网络的标准化和二值化

**关键技术细节**

1. **特征工程**
   - 蛋白质和肽段的聚合统计量(均值、中位数、标准差)
   - 时间序列特征的构造
   - 蛋白质-肽段关系特征的提取

2. **模型架构**
   - **LightGBM**: 梯度提升树模型
   - **Neural Network**: 深度学习模型
   - **集成策略**: 简单平均

3. **数据预处理**
   - NN专用预处理: 特征缩放
   - 特征二值化处理
   - 缺失值处理策略

**代码要点**
```python
# 模型集成示例
final_prediction = (lgb_pred + nn_pred) / 2
```

### 2nd Place - No Luck, All Skill

**核心策略**
- 发布时间: 2023年6月19日
- 强调特征工程的重要性
- 多模型集成策略

**关键特征**
- 详细的特征工程流程
- 模型融合技术
- 验证策略设计

### 3rd Place - Hajime Tamura

**核心策略**
- 发布时间: 2023年5月19日
- **分组策略**: 将数据分成两组分别优化
- 简洁的解决方案(三个主要函数)

**关键创新**
- 数据分组优化
- 针对性模型训练
- 简化流程提升效率

### 4th/5th Place - Ambrosm (#5: Find the Control Group)

**核心策略**
- 发布时间: 2023年5月18日
- **控制组识别**: 关键创新点
- 利用对照组信息改进预测

**关键洞察**
- 识别并分离控制组样本
- 针对不同组别使用不同策略
- 提升模型区分度

### 9th Place - Makotu

**核心策略**
- 发布时间: 2023年5月18日
- 详细的特征工程和模型调优

### 13th Place - FNOA

**技术要点**
- 中等排名的稳定方案
- 实用的特征工程方法

### 43rd Place - Wojciech Victor Fulmyk (Top 3% Silver)

**重要发现**
- **XGBoost 和 LightGBM 表现不佳**
- 强调传统树模型在这个数据集上的局限性
- 探索其他模型方向

**技术要点**
```python
# 他们的发现表明传统 GBDT 可能不是最佳选择
# 需要考虑其他模型或更复杂的特征工程
```

### 89th Place - Giba (Non-Leaky Solution)

**核心策略**
- 强调无数据泄露的干净方案
- 可复现的验证策略

---

## Common Techniques Across Solutions

### 1. Feature Engineering Patterns

**蛋白质/肽段聚合特征**
```python
# 时间聚合
protein_stats = train.groupby('patient_id')['protein'].agg([
    'mean', 'median', 'std', 'min', 'max'
])

# 肽段聚合
peptide_stats = train.groupby('patient_id')['peptide'].agg([
    'mean', 'count', 'nunique'
])
```

**时间序列特征**
- 访问间隔时间
- 进展速度估计
- 基线和随访差异

**蛋白质-肽段关系**
- 蛋白质包含的肽数量
- 肽段来源的蛋白质信息

### 2. Model Selection Insights

**成功模型**
- LightGBM (部分方案)
- Neural Networks / MLP
- 集成方法

**需要谨慎的模型**
- XGBoost (43rd方案指出效果不佳)
- 纯线性模型
- 单一模型(推荐集成)

### 3. Validation Strategies

**关键原则**
- 避免患者级别的数据泄露
- 时间基础的分割
- 分组交叉验证

```python
from sklearn.model_selection import GroupKFold

gkf = GroupKFold(n_splits=5)
for train_idx, val_idx in gkf.split(X, y, groups=patient_ids):
    # 训练和验证
```

### 4. Data Leakage Prevention

**常见陷阱**
- 同一患者的多次访问分散在训练/验证集
- 未来信息泄露到训练集
- 蛋白质/肽段测试集信息泄露

**预防措施**
- 严格的患者级别分割
- 时间有序分割
- 仔细的特征构造审计

---

## Code Templates

### Basic Feature Engineering

```python
import pandas as pd
import numpy as np

def create_protein_features(train_proteins, test_proteins):
    """创建蛋白质聚合特征"""
    def process(df):
        stats = df.groupby('patient_id')['NPX'].agg([
            ('protein_mean', 'mean'),
            ('protein_std', 'std'),
            ('protein_min', 'min'),
            ('protein_max', 'max')
        ]).reset_index()
        return stats

    train_stats = process(train_proteins)
    test_stats = process(test_proteins)

    return train_stats, test_stats

def create_peptide_features(train_peptides, test_peptides):
    """创建肽段聚合特征"""
    def process(df):
        stats = df.groupby('patient_id')['PeptideAbundance'].agg([
            ('peptide_mean', 'mean'),
            ('peptide_std', 'std'),
            ('peptide_count', 'count')
        ]).reset_index()
        return stats

    train_stats = process(train_peptides)
    test_stats = process(test_peptides)

    return train_stats, test_stats

def create_time_features(train_clinical, test_clinical):
    """创建时间序列特征"""
    def process(df):
        df = df.copy()
        df['visit_month'] = df['visit_month'].astype(int)
        df['pred_month'] = df['visit_month'] + df['updrs_test_month']

        # 计算自基线以来的时间
        df['months_since_baseline'] = df.groupby('patient_id')['visit_month'].transform(lambda x: x - x.min())

        return df

    return process(train_clinical), process(test_clinical)
```

### Model Training Template

```python
import lightgbm as lgb
from sklearn.model_selection import GroupKFold
from sklearn.metrics import mean_absolute_error

def smape(y_true, y_pred):
    """SMAPE 评估指标"""
    return 100 * np.mean(2 * np.abs(y_pred - y_true) / (np.abs(y_true) + np.abs(y_pred) + 1e-8))

def train_lightgbm(X_train, y_train, groups, params=None):
    """训练 LightGBM 模型"""
    if params is None:
        params = {
            'objective': 'regression',
            'metric': 'mae',
            'learning_rate': 0.01,
            'num_leaves': 31,
            'max_depth': -1,
            'feature_fraction': 0.8,
            'bagging_fraction': 0.8,
            'bagging_freq': 5,
            'verbose': -1
        }

    gkf = GroupKFold(n_splits=5)
    models = []
    scores = []

    for train_idx, val_idx in gkf.split(X_train, y_train, groups=groups):
        X_tr, X_val = X_train.iloc[train_idx], X_train.iloc[val_idx]
        y_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx]

        train_data = lgb.Dataset(X_tr, label=y_tr)
        val_data = lgb.Dataset(X_val, label=y_val, reference=train_data)

        model = lgb.train(
            params,
            train_data,
            num_boost_round=10000,
            valid_sets=[train_data, val_data],
            callbacks=[lgb.early_stopping(100), lgb.log_evaluation(0)]
        )

        pred = model.predict(X_val)
        score = smape(y_val, pred)

        models.append(model)
        scores.append(score)

    print(f'Average SMAPE: {np.mean(scores):.2f}')

    return models, scores

# 使用示例
# models, scores = train_lightgbm(X_train, y_train, patient_ids)
```

### Neural Network Template

```python
import tensorflow as tf
from sklearn.preprocessing import StandardScaler

def create_nn_model(input_dim, hidden_units=[256, 128, 64]):
    """创建神经网络模型"""
    model = tf.keras.Sequential([
        tf.keras.layers.Input(shape=(input_dim,)),
    ])

    for units in hidden_units:
        model.add(tf.keras.layers.Dense(
            units,
            activation='relu',
            kernel_regularizer=tf.keras.regularizers.l2(0.01)
        ))
        model.add(tf.keras.layers.Dropout(0.3))
        model.add(tf.keras.layers.BatchNormalization())

    model.add(tf.keras.layers.Dense(1, activation='linear'))

    model.compile(
        optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
        loss='mae',
        metrics=['mae']
    )

    return model

def train_nn(X_train, y_train, groups, epochs=100, batch_size=32):
    """训练神经网络"""
    # 标准化
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)

    gkf = GroupKFold(n_splits=5)
    models = []
    scores = []

    for train_idx, val_idx in gkf.split(X_train_scaled, y_train, groups=groups):
        X_tr, X_val = X_train_scaled[train_idx], X_train_scaled[val_idx]
        y_tr, y_val = y_train.iloc[train_idx], y_train.iloc[val_idx]

        model = create_nn_model(X_train.shape[1])

        early_stop = tf.keras.callbacks.EarlyStopping(
            monitor='val_loss',
            patience=10,
            restore_best_weights=True
        )

        history = model.fit(
            X_tr, y_tr,
            validation_data=(X_val, y_val),
            epochs=epochs,
            batch_size=batch_size,
            callbacks=[early_stop],
            verbose=0
        )

        pred = model.predict(X_val).flatten()
        score = smape(y_val, pred)

        models.append((model, scaler))
        scores.append(score)

    print(f'Average SMAPE: {np.mean(scores):.2f}')

    return models, scores
```

### Ensemble Template

```python
def ensemble_predictions(lgb_models, nn_models, X_test):
    """集成多个模型的预测"""
    # LightGBM 预测
    lgb_preds = np.mean([model.predict(X_test) for model in lgb_models], axis=0)

    # NN 预测(需要标准化)
    _, scaler = nn_models[0]
    X_test_scaled = scaler.transform(X_test)
    nn_preds = np.mean([
        model.predict(X_test_scaled).flatten()
        for model, _ in nn_models
    ], axis=0)

    # 简单平均
    final_pred = (lgb_preds + nn_preds) / 2

    return final_pred
```

---

## Best Practices

### 1. Data Understanding

**蛋白质数据特性**
- 227个蛋白质可能来自不同通路
- 部分蛋白质可能高度相关
- 需要探索蛋白质-疾病关系

**肽段数据特性**
- 肽数量远大于蛋白质数
- 多个肽段可能来自同一蛋白质
- 肽段丰度需要归一化

**临床数据特性**
- MDS-UPDRS 评分范围 0-260
- 不同子评分(第一部分到第四部分)
- 访问时间间隔不均匀

### 2. Feature Engineering Guidelines

**DOs**
- ✅ 创建患者级别的聚合特征
- ✅ 利用时间序列信息
- ✅ 探索蛋白质-肽段关系
- ✅ 考虑蛋白质生物学意义
- ✅ 使用领域知识构造特征

**DON'Ts**
- ❌ 在测试集上计算统计量
- ❌ 混合不同患者的未来信息
- ❌ 忽略数据的时间顺序
- ❌ 过度使用目标编码(容易泄露)

### 3. Model Selection Strategy

**推荐流程**
1. 从简单模型开始(线性模型、决策树)
2. 尝试 LightGBM(部分方案有效)
3. 探索神经网络(1st方案使用)
4. 集成多个模型
5. 针对性调整超参数

**模型选择考虑**
- 数据量小 → 简单模型或强正则化
- 特征多 → 特征选择或降维
- 时序特性 → 考虑时间序列模型
- 集成收益 → 尝试模型融合

### 4. Validation Strategy

**推荐方法**
```python
# 患者级别的 Group K-Fold
from sklearn.model_selection import GroupKFold

gkf = GroupKFold(n_splits=5)
for fold, (train_idx, val_idx) in enumerate(gkf.split(X, y, groups=patient_ids)):
    print(f'Fold {fold + 1}')
    # 训练和验证
```

**时间序列分割**
```python
from sklearn.model_selection import TimeSeriesSplit

tscv = TimeSeriesSplit(n_splits=5)
for fold, (train_idx, val_idx) in enumerate(tscv.split(X)):
    # 确保验证集在时间上晚于训练集
```

### 5. Common Pitfalls

**数据泄露**
- ❌ 将同一患者的多次访问分散到训练和验证集
- ❌ 在分割前计算全局统计量
- ❌ 使用未来信息预测过去

**过拟合**
- ❌ 特征过多而样本过少
- ❌ 过度调参导致验证集泄露
- ❌ 复杂模型在小数据集上

**评估偏差**
- ❌ 使用错误的评估指标
- ❌ 忽略 SMAPE 的对称性
- ❌ 不关注预测的分布特性

### 6. Domain Knowledge Integration

**帕金森病相关**
- MDS-UPDRS 评分的临床意义
- 蛋白质标志物的生物学作用
- 疾病进展的非线性特性

**蛋白质组学**
- 质谱数据的技术变异
- 蛋白质-肽段的定量关系
- 缺失值的含义

### 7. Hyperparameter Tuning

**LightGBM 关键参数**
```python
params = {
    'learning_rate': 0.01,      # 降低学习率
    'num_leaves': 31,           # 控制复杂度
    'max_depth': -1,            # 不限制深度
    'min_data_in_leaf': 20,     # 小数据集增大此值
    'feature_fraction': 0.8,    # 特征采样
    'bagging_fraction': 0.8,    # 数据采样
    'bagging_freq': 5,
    'lambda_l1': 0.1,           # L1 正则化
    'lambda_l2': 0.1,           # L2 正则化
}
```

**神经网络关键参数**
```python
# 小数据集推荐
hidden_units = [128, 64, 32]   # 减少层数和单元数
dropout_rate = 0.3              # 增加 dropout
l2_reg = 0.01                   # L2 正则化
learning_rate = 0.001           # 适中学习率
batch_size = 32                 # 小批量
```

---

## Key Takeaways

1. **小样本竞赛特点**
   - 特征工程比模型复杂度更重要
   - 避免过拟合是关键
   - 简单模型集成可能优于复杂单模型

2. **医疗数据特殊性**
   - 需要理解领域知识
   - 数据泄露风险更高
   - 评估指标的临床意义

3. **成功的共同点**
   - 仔细的特征工程
   - 严格的验证策略
   - 模型集成
   - 避免数据泄露

4. **需要注意的陷阱**
   - XGBoost/LightGBM 不是万能的(43rd方案发现)
   - 数据泄露容易但难以发现
   - 小样本的过拟合风险

5. **推荐的学习路径**
   - 从 1st, 2nd, 3rd 方案学习顶级思路
   - 从 5th, 9th 方案学习实用技巧
   - 从 43rd 方案学习失败经验
   - 综合多个方案形成自己的方法

---

## Resources

### Official Writeups
- [1st Place Solution - Connecting Dotts](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/connecting-dotts-1st-place-solution)
- [2nd Place Solution - No Luck, All Skill](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/no-luck-all-skill-2nd-place-solution)
- [3rd Place Solution - Hajime Tamura](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/hajime-tamura-3rd-place-solution)
- [5th Place Solution - Ambrosm](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/ambrosm-5-find-the-control-group)
- [9th Place Solution - Makotu](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/makotu-9th-place-solution)
- [13th Place Solution - FNOA](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/fnoa-13th-place-solution)
- [43rd Place Solution - Wojciech Victor Fulmyk](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/wojciech-victor-fulmyk-43rd-top-3-silver-medal-sol)
- [89th Place Solution - Giba (Non-Leaky)](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/writeups/giba-top-89-non-leaky-solution)

### External Resources
- [H2O.ai Blog: Navigating the Parkinson's Disease Prediction Challenge with AI](https://h2o.ai/blog/2023/winners-insight-navigating-the-parkinsons-disease-prediction-challenge-with-ai/)
- [中文复现: 小样本比赛也能有稳定区分度](https://zhuanlan.zhihu.com/p/669527953)

### Competition Pages
- [Main Competition Page](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction)
- [Data Description](https://www.kaggle.com/competitions/amp-parkinsons-disease-progression-prediction/data)
- [Discussion Forum](https://www.kaggle.com/c/amp-parkinsons-disease-progression-prediction/discussion)

### Code Notebooks
- [LightGBM Starter with Added Features](https://www.kaggle.com/code/sijovm/lightgbm-starter-with-added-features)
- [XGB Baseline with Added Features](https://www.kaggle.com/code/sijovm/xgb-baseline-with-added-features)
- [AMP® - PDPP EDA + TF Model](https://www.kaggle.com/code/callmewenhao/amp-pdpp-eda-tf-model)
- [AMP® - PDPP EDA](https://www.kaggle.com/code/gunesevitan/amp-pdpp-eda)