1 项目背景与研究目标

泰坦尼克号乘客生存预测是 Kaggle 入门竞赛中最具代表性的二分类案例。任务要求根据乘客登船前已知的信息预测是否生还,适合展示结构化数据清洗、类别特征编码、缺失值处理、特征工程和分类模型评价。

本案例的目标不是单纯追求某一次划分上的最高准确率,而是建立一套可复现、可解释的数据分析流程,并说明每幅图对后续建模决策的影响。

  • 识别数据缺失、类别不均衡和潜在信息冗余。
  • 分析性别、舱位、年龄、家庭结构和登船港口与生还率的关系。
  • 构造能够表达社会身份、同行关系、甲板位置和团体购票的衍生特征。
  • 比较四类常用分类模型,并通过交叉验证控制偶然性。
  • 使用混淆矩阵、ROC-AUC、阈值曲线和特征系数解释最终模型。

2 数据来源与字段说明

数据来源于 Kaggle  竞赛的训练数据公开镜像,共 891 行、12 列。目标字段 Survived 中,1 表示生还,0 表示未生还。

字段

含义

建模处理

PassengerId

乘客编号

仅作标识,不进入模型

Survived

是否生还

目标变量

Pclass

舱位等级

作为类别变量独热编码

Name

姓名

提取称谓 Title

Sex

性别

类别变量

Age

年龄

中位数填补并标准化

SibSp / Parch

同行亲属数量

构造家庭规模

Ticket

票号

统计同票号人数

Fare

票价

标准化并构造人均票价

Cabin

舱室号

提取甲板首字母,缺失标记为未知

Embarked

登船港口

众数填补并独热编码

数据文件:titanic.csv;Notebook:Titanic_生存预测_完整分析.ipynb。

3 技术路线与评价指标

数据按照 75% 训练集和 25% 测试集划分,并使用 Survived 进行分层抽样,以保持两部分样本中的生还比例一致。模型选择阶段在训练集内部执行五折分层交叉验证。

指标

含义

本案例中的作用

准确率

全部样本中预测正确的比例

反映总体判断正确率,但会受到类别比例影响

精确率

预测生还样本中实际生还的比例

衡量生还预测的可信度

召回率

实际生还样本中被识别出的比例

衡量漏掉生还乘客的程度

F1 值

精确率和召回率的调和平均

综合评价生还类别

ROC-AUC

不同阈值下的整体排序能力

作为调参和模型比较的核心指标

3.1 字段缺失率

quality = pd.DataFrame({
    '数据类型': df.dtypes.astype(str),
    '缺失数量': df.isna().sum(),
    '缺失率(%)': (df.isna().mean() * 100).round(2),
    '唯一值数量': df.nunique(dropna=False)
}).sort_values('缺失率(%)', ascending=False)
print(f'完全重复的记录数:{df.duplicated().sum()}')
display(quality)

missing = quality.query('`缺失数量` > 0').sort_values('缺失率(%)')
plt.figure(figsize=(9.0, 4.8))
plt.barh(missing.index, missing['缺失率(%)'], color=PALETTE[0])
plt.xlabel('缺失率(%)')
plt.ylabel('字段')
plt.title('图1 主要字段缺失率')
for i, value in enumerate(missing['缺失率(%)']):
    plt.text(value + 0.8, i, f'{value:.1f}%', va='center')
save_show('01_字段缺失率.png')

Cabin 缺失率约为 77.1%,若直接删除缺失记录会造成大规模样本损失。更合理的方案是保留“是否已知舱室”和甲板首字母信息,并把缺失甲板编码为未知类别。

3.2 生存结果分布

891 名乘客中有 342 人生还、549 人未生还,总体生还率为 38.38%。未生还样本占比约为 61.6%,属于中等程度类别不均衡。

该分布说明准确率不能作为唯一评价标准。假设模型全部预测为未生还,也能获得约 61.6% 的准确率,但完全无法识别生还乘客。因此后续同时报告召回率、F1 值和 ROC-AUC。

3.3 性别与生还率

女性乘客生还率约为 74.2%,男性乘客约为 18.9%,差距超过 55 个百分点。性别是数据中最强的单一解释变量之一。

3.4 舱位等级与生还率

一等舱、二等舱和三等舱的生还率依次下降,约为 63.0%、47.3% 和 24.2%。舱位具有清晰的等级效应。

3.5 年龄组与生还率、

3.6 家庭规模与生还率

family_df = df.assign(FamilySize=df['SibSp'] + df['Parch'] + 1)
family_rate = family_df.groupby('FamilySize')['Survived'].agg(['mean', 'count'])
family_plot = family_rate[family_rate['count'] >= 8]
plt.figure(figsize=(9.0, 5.2))
plt.plot(family_plot.index, family_plot['mean'] * 100,
         marker='o', linewidth=2.5, markersize=7, color=PALETTE[0])
plt.fill_between(family_plot.index, family_plot['mean'] * 100, alpha=0.12, color=PALETTE[0])
plt.xlabel('家庭同行人数')
plt.ylabel('生还率(%)')
plt.title('图6 家庭规模与生还率')
save_show('06_家庭规模与生还率.png')
display(family_rate.rename(columns={'mean':'生还率','count':'人数'}))

独自出行乘客的生还率偏低,2—4 人小家庭的生还率较高;家庭规模过大后,生还率明显下降。

该关系不是简单线性变化,因此同时保留家庭规模和独行标记。小家庭成员可能更容易互相照应,大型家庭在紧急撤离时则面临更高的协调难度。

3.7 港口与舱位的联合关系

pivot = df.pivot_table(index='Pclass', columns='Embarked', values='Survived', aggfunc='mean')
pivot = pivot.reindex(index=[1,2,3], columns=['C','Q','S'])
plt.figure(figsize=(7.6, 5.2))
img = plt.imshow(pivot.values*100, cmap='YlGnBu', vmin=0, vmax=100, aspect='auto')
plt.xticks(range(3), ['瑟堡 C','皇后镇 Q','南安普顿 S'])
plt.yticks(range(3), ['一等舱','二等舱','三等舱'])
plt.title('图7 登船港口与舱位组合的生还率')
for i in range(pivot.shape[0]):
    for j in range(pivot.shape[1]):
        value = pivot.iloc[i,j]
        if pd.notna(value):
            plt.text(j, i, f'{value*100:.1f}%', ha='center', va='center',
                     color='white' if value>0.55 else 'black', fontweight='bold')
cb = plt.colorbar(img)
cb.set_label('生还率(%)')
save_show('07_港口舱位生还率.png')

同一港口内部仍存在明显舱位差异,说明舱位效应并非由港口构成完全解释。瑟堡登船者中一等舱比例较高,若只比较港口总体生还率,容易受到乘客结构的混杂影响。

4 特征工程与预处理

原始姓名、票号和舱室号不能直接输入常规模型,因此从中提取可解释的结构化变量。称谓用于表达年龄、性别和社会身份;甲板首字母作为船舱位置的粗略表示;同票号人数用于识别家庭或团体购票;人均票价用于减少共票导致的票价偏差。

衍生特征

计算方式

预期作用

Title

从 Name 提取称谓

补充年龄、性别和身份信息

FamilySize

SibSp + Parch + 1

描述同行家庭规模

IsAlone

FamilySize 是否等于 1

识别独行乘客

CabinDeck

Cabin 的首字母,缺失记 U

近似表示甲板位置

TicketGroupSize

同一 Ticket 的出现次数

识别团体购票

FarePerPerson

Fare / TicketGroupSize

估计实际人均票价

数值变量使用中位数填补和标准化;类别变量使用众数填补和独热编码。预处理与模型封装为同一 Pipeline,保证每一折交叉验证只在训练折拟合填补值、缩放参数和编码类别。

4.1 多模型表现比较

梯度提升树和随机森林在交叉验证 ROC-AUC 上具有一定优势,说明非线性关系确实存在;逻辑回归在固定测试集上的准确率和 F1 值较为稳定,整体差距并不大。

模型

交叉验证ROC-AUC

测试集准确率

测试集F1

测试集ROC-AUC

梯度提升树

0.8884

0.7982

0.7239

0.8535

随机森林

0.8794

0.7892

0.7186

0.8524

支持向量机

0.8668

0.8027

0.7349

0.8587

逻辑回归模型

0.8650

0.8296

0.7765

0.8613

4.2 参数调优结果

指标

测试集结果

准确率

0.8117

精确率

0.7683

召回率

0.7326

F1 值

0.7500

ROC-AUC

0.8608

4.3 混淆矩阵

4.4 ROC 曲线

plt.figure(figsize=(8.2,6.0))
for name, model in fitted_models.items():
    prob = model.predict_proba(X_test)[:,1]
    fpr,tpr,_ = roc_curve(y_test,prob)
    auc = roc_auc_score(y_test,prob)
    plt.plot(fpr,tpr,linewidth=2,label=f'{name}(AUC={auc:.3f})')
fpr,tpr,_=roc_curve(y_test,final_prob)
plt.plot(fpr,tpr,linewidth=3,linestyle='--',color='black',label=f'调优逻辑回归(AUC={roc_auc_score(y_test,final_prob):.3f})')
plt.plot([0,1],[0,1],linestyle=':',color='gray',label='随机判断')
plt.xlabel('假阳性率')
plt.ylabel('真阳性率')
plt.title('图10 不同模型的ROC曲线')
plt.legend(frameon=False,loc='lower right')
save_show('10_ROC曲线.png')

所有模型曲线均明显高于随机判断线,测试集 AUC 位于约 0.85—0.86 区间,具有较好的概率排序能力。

4.5 分类阈值分析

thresholds = np.linspace(0.20,0.80,61)
threshold_rows=[]
for t in thresholds:
    pred_t=(final_prob>=t).astype(int)
    threshold_rows.append({'阈值':t,'精确率':precision_score(y_test,pred_t,zero_division=0),
                           '召回率':recall_score(y_test,pred_t,zero_division=0),
                           'F1值':f1_score(y_test,pred_t,zero_division=0)})
threshold_df=pd.DataFrame(threshold_rows)
best_f1_row=threshold_df.loc[threshold_df['F1值'].idxmax()]
plt.figure(figsize=(9.0,5.5))
plt.plot(threshold_df['阈值'],threshold_df['精确率'],label='精确率',linewidth=2.2,color=PALETTE[0])
plt.plot(threshold_df['阈值'],threshold_df['召回率'],label='召回率',linewidth=2.2,color=PALETTE[4])
plt.plot(threshold_df['阈值'],threshold_df['F1值'],label='F1值',linewidth=2.5,color=PALETTE[1])
plt.axvline(0.5,linestyle='--',color='gray',label='默认阈值0.5')
plt.axvline(best_f1_row['阈值'],linestyle=':',color='black',label=f"最佳F1阈值{best_f1_row['阈值']:.2f}")
plt.xlabel('分类阈值')
plt.ylabel('指标值')
plt.title('图11 分类阈值对模型指标的影响')
plt.legend(frameon=False)
save_show('11_阈值分析.png')
print(best_f1_row)

阈值升高时,模型判定生还更谨慎,精确率通常上升而召回率下降;阈值降低则相反。默认 0.5 并不是任何场景下都最优。

4.6 特征系数解释

女性、一等舱以及 Mrs、Miss 等称谓通常提高预测生还概率;男性、三等舱和 Mr 称谓通常降低预测生还概率,方向与探索性分析一致。

5 结论、局限性与改进建议

  • 性别、舱位等级和称谓是最重要的生还预测因素,家庭规模、甲板和票组信息提供补充解释。
  • 最终逻辑回归测试集准确率为 81.17%,ROC-AUC 为 0.8608,性能与可解释性较为均衡。
  • 数据量较小,单次测试集指标可能受到划分影响;建议使用重复分层交叉验证报告均值和标准差。
  • 同一家庭或同票号乘客可能同时出现在训练集和测试集,后续可尝试基于家庭/票号的分组验证。
  • 可进一步尝试 CatBoost、XGBoost、模型融合和概率校准,并使用折外预测确定分类阈值。

具体细节见原文

创造不易,谢谢各位多多点赞收藏!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐