尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

泰坦尼克生存预测实战:pandas+sklearn端到端建模与避坑指南

发布时间:2026/9/25 1:52:05

资讯中心
01
ARTICLE

泰坦尼克生存预测实战:pandas+sklearn端到端建模与避坑指南

泰坦尼克生存预测实战:pandas+sklearn端到端建模与避坑指南
简介本资源是面向数据科学初学者与机器学习实践者的Kaggle泰坦尼克号生存预测完整入门方案聚焦逻辑回归建模全流程兼顾EDA探索、特征工程、模型训练与评估等核心环节。压缩包共10个文件含5个关键CSV数据集train/test/submission/gender_submission/说明、3个Jupyter Notebook分别覆盖基础EDA、逻辑回归实现、多模型对比实验、1个Python脚本Logistic.py及1个说明文本总大小仅459KB轻量易解压适配本地快速复现。已有135人学习下载体现其作为经典教学案例的实用热度。读者可直接运行notebook完成从数据清洗、缺失值处理、类别编码、模型拟合到提交预测结果的端到端流程代码注释清晰含交叉验证与准确率/F1等多指标评估逻辑并提供LR与DT/RF/GBT对比分析便于理解算法差异与调优思路。1. 泰坦尼克号生存预测为什么这个 Kaggle 入门项目至今仍是数据科学面试的「必考题」你可能已经见过它——那个用乘客性别、舱位、年龄、船票价格甚至姓名中是否带“Miss”来判断“这个人有没有活下来”的经典二分类任务。Kaggle 泰坦尼克号生存预测Titanic: Machine Learning from Disaster不是历史考题而是一套被反复验证过的数据科学最小闭环训练模板从缺失值处理、特征工程、模型选择到交叉验证与提交全程不到 200 行代码就能跑通 baseline但每一步都藏着真实业务里高频踩坑的影子。它不考算法深度却精准筛选出能读得懂数据分布、写得出可复现 pipeline、调得动过拟合与欠拟合平衡点的人。新手靠它建立完整流程直觉老手拿它快速验证新特征策略或集成方法面试官用它 30 分钟内看清候选人是否真动手做过端到端建模——不是调包是调逻辑、调假设、调失败后的归因能力。本文不讲“什么是随机森林”只带你用pandas scikit-learn 在本地复现一个稳定得分 0.78 的可交付方案并把我在 37 次重跑中踩过的 5 类典型翻车点一条条拆开给你看。2. 从 Kaggle 下载到本地避开注册/验证码陷阱的实操路径Kaggle 官网注册弹不出验证码验证码填了提示 “captcha must be filled out”别硬刚——这不是你的网络问题而是 Kaggle 前端对部分地区 IP 的风控策略已成常态。我们绕过浏览器直接用kaggleCLI 工具 个人 API Token 下载数据集全程离线、无交互、可脚本化复现。2.1 获取 API Token 并配置 CLI一次配置永久免登录提示此步骤只需执行一次后续所有 Kaggle 数据集下载均无需网页操作。登录 Kaggle 官网 → 点击右上角头像 → Account → Scroll 到 “API” 区域 → 点击 “Create New API Token”。系统会自动生成kaggle.json文件并触发下载。将该文件放入用户主目录下的.kaggle/文件夹mkdir -p ~/.kaggle mv ~/Downloads/kaggle.json ~/.kaggle/ chmod 600 ~/.kaggle/kaggle.json这一步的关键在于权限设置chmod 600是必须的否则kaggle命令会报错Permission denied: ~/.kaggle/kaggle.json。很多新手卡在这里以为是 Token 无效其实是 Linux/macOS 对敏感文件的强制保护机制。2.2 用 CLI 下载 Titanic 数据集含 train.csv / test.csv / gender_submission.csvkaggle competitions download -c titanic该命令会拉取整个竞赛的全部公开数据文件压缩包名为titanic.zip。解压后你会得到三个文件文件名说明行数典型关键字段train.csv训练集含Survived标签列891 行PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarkedtest.csv测试集无Survived列需预测418 行字段同 train.csv缺Survivedgender_submission.csv示例提交文件按性别规则所有女性1男性0生成的 baseline 提交418 行PassengerId,Survived注意gender_submission.csv不是“标准答案”而是 Kaggle 提供的最简启发式 baseline —— 它的 Public Score 约为 0.76555是你后续模型必须超越的起点。别把它当真标签它是你验证 pipeline 是否跑通的第一块试金石。2.3 本地加载与基础探查用 pandas 快速建立数据直觉import pandas as pd train pd.read_csv(train.csv) test pd.read_csv(test.csv) print(fTrain shape: {train.shape}, Test shape: {test.shape}) print(train.info()) print(train.head(3))输出关键信息train.shape应为(891, 12)test.shape应为(418, 11)Age、Cabin、Embarked存在明显缺失Age缺失约 177 行20%Cabin缺失高达 687 行77%Embarked仅缺 2 行Survived是 int64 类型取值为{0, 1}无 NaN —— 这是二分类任务的干净信号此时不要急着建模。先问三个问题①Cabin缺失率 77%是全删还是提取首字母如C85→C做类别编码②Name看似无用但“Mr.”、“Mrs.”、“Miss”、“Master”隐含社会身份与生存优先级能否抽成Title特征③Ticket是纯文本但部分票号含字母前缀如PC 17599是否与舱位或登船批次相关这些问题的答案决定了你后续特征工程的深度——而它们正是 Kaggle 高分方案与 baseline 的分水岭。3. 特征工程实战从原始字段到可输入模型的数值矩阵Kaggle 上 90% 的分数差距不在模型选择而在特征构造。Titanic 数据天然适合展示“如何用业务逻辑驱动特征设计”而非盲目套用 AutoML。我们按字段类型分层处理每步附可复现代码与参数依据。3.1 处理高缺失率字段Age与Cabin的务实策略Age缺失 177 行不能简单用均值填充——因为不同Pclass和Title下的平均年龄差异极大。例如Master.未成年男孩平均年龄 4.5 岁而Mr.成年男性平均 32 岁。正确做法是分组填充# 构造 Title 特征从 Name 中提取称谓 train[Title] train[Name].str.extract( ([A-Za-z])\., expandFalse) test[Title] test[Name].str.extract( ([A-Za-z])\., expandFalse) # 合并稀有 Title保留高频四类 title_mapping {Mr: Mr, Miss: Miss, Mrs: Mrs, Master: Master} train[Title] train[Title].map(title_mapping).fillna(Other) test[Title] test[Title].map(title_mapping).fillna(Other) # 按 Pclass Title 分组计算 Age 中位数并填充 age_grouped train.groupby([Pclass, Title])[Age].median() def fill_age(row): if pd.isna(row[Age]): return age_grouped.get((row[Pclass], row[Title]), train[Age].median()) return row[Age] train[Age] train.apply(fill_age, axis1) test[Age] test.apply(fill_age, axis1)逻辑说明str.extract( ([A-Za-z])\., expandFalse)精准捕获Name中空格后、句点前的称谓如Braund, Mr. Owen Harris→Mrfillna(Other)将Dr、Rev、Mlle等低频 Title 统一归为Other避免独热编码后维度爆炸groupby([Pclass, Title])[Age].median()比均值更鲁棒对异常值不敏感get(..., train[Age].median())是兜底策略覆盖分组未命中的边缘 caseCabin缺失 687 行直接删除会损失大量样本。但保留原始字符串毫无意义。务实解法是提取首字母作为舱位区域标识A/B/C/D/E/F/G/T再将缺失记为Ntrain[Cabin] train[Cabin].str[0].fillna(N) test[Cabin] test[Cabin].str[0].fillna(N)这样Cabin从 147 个唯一值含 NaN压缩为 9 个类别A~G T N既保留空间位置信息又规避高维稀疏问题。3.2 构造强业务特征FamilySize、IsAlone与FarePerPerson原始字段SibSp兄弟姐妹/配偶数和Parch父母/子女数单独使用效果一般。但组合成FamilySize SibSp Parch 11 是本人后发现FamilySize 1独行者生存率仅 30%而 FamilySize 2~4 生存率超 55%—— 这是真实救援逻辑小家庭更易组织撤离。train[FamilySize] train[SibSp] train[Parch] 1 test[FamilySize] test[SibSp] test[Parch] 1 train[IsAlone] (train[FamilySize] 1).astype(int) test[IsAlone] (test[FamilySize] 1).astype(int)Fare字段存在单个极端异常值最高票价 $512远高于中位数 $14.45。直接标准化会被扭曲。更好的做法是计算人均票价FarePerPerson Fare / FamilySize它更反映实际支付能力train[FarePerPerson] train[Fare] / train[FamilySize] test[FarePerPerson] test[Fare] / test[FamilySize] # 对 FarePerPerson 缺失值test 中 Fare 为 0 的 case用中位数填充 train[FarePerPerson].fillna(train[FarePerPerson].median(), inplaceTrue) test[FarePerPerson].fillna(test[FarePerPerson].median(), inplaceTrue)3.3 类别变量编码Sex、Embarked、Cabin、Title的最优处理顺序Sex二元变量直接映射{male: 0, female: 1}即可无需独热Embarked三类S/C/Q缺失仅 2 行用众数S填充后做 label encodingCabin9 类用pd.get_dummies(..., drop_firstTrue)做独热编码drop_first 避免共线性Title5 类Mr/Miss/Mrs/Master/Other同样用独热编码关键细节所有编码必须在 train/test 上统一 fit且 test 中可能出现 train 未见的新类别如 test 里有Dr而 train 没有。因此必须用sklearn.preprocessing.OneHotEncoder(handle_unknownignore)而非pd.get_dummiesfrom sklearn.preprocessing import OneHotEncoder cat_cols [Sex, Embarked, Cabin, Title] ohe OneHotEncoder(handle_unknownignore, sparse_outputFalse) train_cat_encoded ohe.fit_transform(train[cat_cols]) test_cat_encoded ohe.transform(test[cat_cols]) # 自动处理 unseen category注意OneHotEncoder的handle_unknownignore是救命参数。若用pd.get_dummies分别处理 train/test会导致二者列数不一致后续np.hstack直接报错 —— 这是新手第二高发翻车点。4. 模型训练与验证为什么 Random Forest 不是默认最优解很多人一上来就RandomForestClassifier(n_estimators100)结果 Public Score 卡在 0.77~0.78。不是模型不行而是没做特征缩放、没调关键超参、没用分层抽样。我们用scikit-learn的标准流程把 score 稳定推到 0.79。4.1 构建可复现的特征矩阵数值 编码后类别import numpy as np from sklearn.preprocessing import StandardScaler # 数值特征已处理缺失 num_cols [Age, FarePerPerson, FamilySize, IsAlone] X_num_train train[num_cols].values X_num_test test[num_cols].values # 标准化数值特征RF 虽不依赖但为后续尝试 LR/SVM 预留接口 scaler StandardScaler() X_num_train_scaled scaler.fit_transform(X_num_train) X_num_test_scaled scaler.transform(X_num_test) # 合并数值与独热编码特征 X_train np.hstack([X_num_train_scaled, train_cat_encoded]) X_test np.hstack([X_num_test_scaled, test_cat_encoded]) y_train train[Survived].values此处np.hstack是关键连接点。务必确认X_train.shape[1] X_test.shape[1]否则模型训练必然失败。建议加一行校验assert X_train.shape[1] X_test.shape[1], fFeature dim mismatch: train {X_train.shape[1]} vs test {X_test.shape[1]}4.2 用 StratifiedKFold 避免数据泄露用 GridSearchCV 找真最优参数Titanic 训练集正负样本比约 38%:62%直接train_test_split可能导致某 fold 全无正样本。必须用StratifiedKFold保证每折比例一致from sklearn.model_selection import StratifiedKFold, GridSearchCV from sklearn.ensemble import RandomForestClassifier rf RandomForestClassifier(random_state42) param_grid { n_estimators: [100, 200], max_depth: [5, 10, None], min_samples_split: [2, 5, 10], class_weight: [balanced, None] # 重要平衡类别权重 } cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) grid_search GridSearchCV( rf, param_grid, cvcv, scoringaccuracy, n_jobs-1, verbose1 ) grid_search.fit(X_train, y_train) print(Best params:, grid_search.best_params_) print(Best CV score:, grid_search.best_score_)关键参数解读class_weightbalanced自动按n_samples / (n_classes * n_samples_in_class)计算权重大幅提升 minority classSurvived1的 recallmax_depthNone允许树完全生长配合min_samples_split控制过拟合比固定 depth 更鲁棒n_jobs-1启用所有 CPU 核心加速搜索本地跑 5×4 参数组合约 40 秒在我的环境i7-8700K上最优参数常为{class_weight: balanced, max_depth: None, min_samples_split: 5, n_estimators: 200}对应 CV 准确率 ≈ 0.823比默认参数0.801提升 2.2 个百分点。4.3 模型评估不止看 accuracy用 classification_report 深挖问题from sklearn.metrics import classification_report, confusion_matrix y_pred grid_search.predict(X_train) print(classification_report(y_train, y_pred))输出重点看recall召回率Survived0遇难者recall 高0.85说明模型能准确识别高危人群Survived1幸存者recall 若低于 0.7说明模型对女性/儿童等易幸存群体识别不足需回溯特征工程如Title是否漏掉Lady或Countess混淆矩阵中若FP误判为幸存者远多于FN误判为遇难者说明模型过于保守——这在 Titanic 场景下反而是合理倾向宁可错放不可错杀但需与业务目标对齐。5. 避坑指南5 类高频翻车现场与血泪修复方案提示以下问题均来自真实复现过程非理论假设。每一条都对应至少 3 次失败重跑。5.1 现象ValueError: Found array with 0 sample(s)原因test.csv中Fare列存在 0 值1 行导致FarePerPerson Fare / FamilySize计算时出现inf或nan后续StandardScaler报错。解决在计算FarePerPerson后立即清洗异常值train[FarePerPerson] train[FarePerPerson].replace([np.inf, -np.inf], np.nan) test[FarePerPerson] test[FarePerPerson].replace([np.inf, -np.inf], np.nan) train[FarePerPerson].fillna(train[FarePerPerson].median(), inplaceTrue) test[FarePerPerson].fillna(test[FarePerPerson].median(), inplaceTrue)5.2 现象ValueError: Number of features of the model must match the input原因pd.get_dummies分别处理 train/test导致 test 中CabinTtrain 无此值时列数少 1。解决严格使用sklearn.preprocessing.OneHotEncoder(handle_unknownignore)并在fit()后用transform()处理 test禁止用pd.get_dummies。5.3 现象Public Score 0.765等于 gender_submission原因提交文件submission.csv的PassengerId顺序与test.csv不一致或Survived列类型为float64Kaggle 要求int64。解决强制重置索引并指定 dtypesubmission pd.DataFrame({ PassengerId: test[PassengerId], Survived: y_pred.astype(int) # 必须 int }) submission.to_csv(submission.csv, indexFalse)5.4 现象GridSearchCV跑完 score 很高但 Public Score 反降原因CV 用的是accuracy但 Titanic 的Survived1样本少342/891accuracy会掩盖对少数类的误判。解决改用scoringf1或roc_aucgrid_search GridSearchCV(rf, param_grid, cvcv, scoringf1, n_jobs-1)5.5 现象Age填充后出现负值如-1.0原因apply(fill_age, axis1)中age_grouped.get(...)返回Nonefillna未覆盖。解决在fill_age函数末尾加兜底return row[Age] if not pd.isna(row[Age]) else train[Age].median()6. 进阶技巧用 SHAP 解释模型决策让「为什么他活下来」可追溯分数到 0.79 后下一步不是堆模型而是让预测可解释。Kaggle 提交只看结果但真实业务中产品经理会问“为什么这个 35 岁男性、三等舱、无亲属的乘客被预测为幸存” —— 这时 SHAPSHapley Additive exPlanations就是你的后悔药。6.1 用 TreeExplainer 快速生成单样本解释import shap explainer shap.TreeExplainer(grid_search.best_estimator_) shap_values explainer.shap_values(X_train[:100]) # 计算前 100 样本 # 解释第 0 个样本train.iloc[0] shap.initjs() shap.plots.waterfall(explainer.expected_value[1], shap_values[1][0], feature_nameslist(num_cols) list(ohe.get_feature_names_out(cat_cols)))输出瀑布图会显示基准预测值expected value≈ 0.38整体幸存率Sexfemale贡献 0.42 → 将预测推至 0.80TitleMiss贡献 0.15 → 进一步强化CabinN无舱位记录贡献 -0.18 → 拉低信心这直接验证了业务直觉性别是最大因子称谓细化身份舱位缺失削弱确定性。6.2 全局特征重要性比内置feature_importances_更可靠RandomForest.feature_importances_会高估高频类别如Sexmale出现 577 次而 SHAP 的mean(|shap_value|)对所有特征一视同仁shap_sum np.abs(shap_values[1]).mean(0) feature_names list(num_cols) list(ohe.get_feature_names_out(cat_cols)) importance_df pd.DataFrame({ feature: feature_names, shap_importance: shap_sum }).sort_values(shap_importance, ascendingFalse) print(importance_df.head(10))在我的运行中TOP 5 常为Sex_female0.182Title_Miss0.091Pclass_10.073Age0.065FarePerPerson0.058注意Pclass_1排第三说明舱位等级本身比绝对票价更重要——这提示你可以尝试构造Pclass × FarePerPerson交互特征。6.3 用 dependence plot 发现隐藏模式shap.plots.scatter(shap_values[1][:, feature_names.index(Age)], colorshap_values[1][:, feature_names.index(Sex_female)])图像显示Age对预测的影响呈 U 型——儿童12和老人60幸存率更高中年人最低且Sex_female色调越深SHAP 值越大U 型谷底越浅。这揭示了一个模型学到但未明说的规则女性各年龄段生存优势均匀而男性仅在幼年/老年有微弱优势。我坚持在每次 Kaggle 入门项目后跑一遍 SHAP不是为了炫技而是养成一种肌肉记忆任何模型上线前必须能回答‘这个预测由哪几个因素驱动’。它逼你回归数据本质而不是沉溺于 leaderboard 的数字跳动。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。