ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python泰坦尼克号项目实战:从数据清洗到模型预测完整流程

Python泰坦尼克号项目实战:从数据清洗到模型预测完整流程 简介本资源是面向Python数据科学初学者与Kaggle入门者的泰坦尼克号生存预测实战项目完整覆盖数据清洗、探索性分析、特征工程、模型训练与评估全流程解决机器学习项目落地中常见的缺失值处理、类别编码、模型对比与交叉验证等核心问题。压缩包共4个文件2个CSV数据集train.csv与test.csv提供原始竞赛数据1个Python脚本.py实现Pandas数据预处理、Seaborn可视化、Scikit-learn多模型构建含逻辑回归、随机森林等及网格搜索调优1份Word实验报告.doc系统梳理分析思路、关键代码说明与结果解读。资源大小仅2.35MB轻量易用结构清晰代码注释充分报告图文并茂便于边学边练、对照复现与理解建模逻辑。目前已有5180人学习下载是掌握数据分析完整工作流的高性价比入门范例。 不少人第一次下载“python泰坦尼克号.zip”这类资源时以为只是解压、跑个脚本就完事了结果卡在第一步打不开压缩包或者环境没配好代码一跑全是红色报错。说实话这个项目是数据分析与机器学习入门绕不开的经典案例数据量不大、字段清晰、问题明确非常适合用来走通一条完整的建模流程。这篇文章就围绕这个zip从解压、环境准备、数据处理、特征工程到模型训练把整个链路拆开讲透帮你把这份资源真正用起来。1. 先搞懂压缩包里装的是什么1.1 一份标准泰坦尼克号项目的文件清单正常情况下一份完整的泰坦尼克号项目压缩包至少应该包含下面这几类内容train.csv训练集通常是891行12列包含乘客的各种属性以及是否幸存Survived这一标签。test.csv测试集一般是418行没有Survived列这是需要你去预测的部分。gender_submission.csv一个最简单的基准提交样例展示的是“所有女性都幸存、所有男性都遇难”这种极端假设下的预测结果。脚本文件可能是Titanic.ipynb、main.py或者analysis.py承载了大部分分析和建模代码。说明文档可能是README或者一个简单的txt里面写明了项目背景、运行方式、依赖库等。如果你拿到的压缩包和这个清单差得很远比如只有代码没有数据或者数据不完整这时候先别急着改代码你需要先自己想办法补齐数据Kaggle官方页面可以下载原始csv。这是我在处理很多开源项目时的一个习惯先把文件清单列出来跟标准结构对比能少走很多弯路。1.2 解压前先确认真的是zip吗经常有人问我“为什么zip解压报错”其实问题往往出在文件格式本身。最常见的一种情况是文件后缀是.zip但实际上并不是一个真正的zip文件。可能是下载过程中网络中断导致文件损坏也可能是源文件本身用了其他压缩格式但改了后缀名。在Linux或macOS下我通常会先用file命令看一下真实格式file titanic.zip如果输出类似“Zip archive data”说明它是正常的zip。如果输出是“gzip compressed data”或“7-zip archive data”说明扩展名和实际格式对不上这时候把后缀改成对应格式再去解压就能解决。如果输出显示“data”或者“empty”那基本可以断定文件已经损坏了。Windows下没有file命令可以用Python来快速验证import zipfile try: with zipfile.ZipFile(titanic.zip, r) as z: print(z.namelist()) except zipfile.BadZipFile as e: print(文件损坏或不是zip格式:, e)如果文件只是轻微损坏可以试试用zip -FF修复zip -FF titanic.zip --out titanic_fixed.zip这里多说一句zip格式的完整性依赖于文件末尾的EOCDEnd of Central Directory记录也就是中心目录结束标记。很多解压工具在扫描不到这个标记时就会报“could not find eocd”但文件头部可能有部分有效数据。所以遇到这种报错不要下意识觉得是解压软件的问题先检查文件本身。2. 环境准备让Python顺畅跑起来2.1 从零安装Python并验证如果你电脑上还没装Python建议直接去Python官网下载3.9到3.11之间的版本我现在用的是3.10兼容性好各大数据分析库都支持得不错。安装的时候有两点需要注意第一安装界面上一定要勾选“Add Python to PATH”否则后面在命令行里输入python会提示找不到命令。第二安装完成后打开命令行Windows的cmd或PowerShellmacOS的Terminal输入python --version如果输出了Python版本号说明安装成功。很多人喜欢用Anaconda来管理环境我这里再说一句Anaconda对入门者更友好因为它自带了很多数据分析库不需要逐个安装。但如果你更想保持一个轻量级的环境纯Python加pip也完全够用。这个选择不影响后续代码逻辑只是依赖管理方式不同。2.2 安装数据分析与机器学习依赖泰坦尼克号项目用到的核心库并不多pandas负责数据读取和清洗numpy负责数值计算matplotlib和seaborn负责可视化scikit-learn负责建模和评估。直接在命令行执行pip install pandas numpy matplotlib seaborn scikit-learn如果下载速度慢可以用国内镜像源这个并不涉及特殊网络操作只是换一个下载服务器地址比如清华源pip install pandas numpy matplotlib seaborn scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后打开Python交互环境或者写个临时脚本验证一下版本号import pandas as pd import numpy as np import sklearn print(pd.__version__) print(np.__version__) print(sklearn.__version__)我遇到过不少人在这步就把版本升到了最新版结果某些函数接口不兼容代码跑不通。如果你拿到的是别人的老代码建议不要盲目追求新版本能跑通比版本新更重要。3. 数据探索先看清泰坦尼克号的真实面貌3.1 导入数据与整体认知环境准备好了以后第一件事不是急着建模而是把数据读进来看看它到底长什么样。import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns train pd.read_csv(train.csv) test pd.read_csv(test.csv) print(train.shape) print(test.shape) print(train.head()) print(train.info())输出train.shape应该是(891, 12)test.shape应该是(418, 11)。这个12列和11列的差异就在于Survived标签列。train.info()会列出每一列的类型和非空值数量。这一步的价值在于让你快速发现两件事哪些列有缺失值以及哪些列的类型需要转换。先记住几个关键字段的含义Pclass船舱等级1等舱、2等舱、3等舱SibSp同行的兄弟姐妹或配偶数量Parch同行的父母或子女数量Fare船票价格Embarked登船港口C代表瑟堡Q代表皇后镇S代表南安普顿Cabin船舱编号3.2 缺失值盘点Age、Cabin、Embarked用一行代码可以快速查看缺失情况print(train.isnull().sum())在我的经验里三个字段基本一定会有缺失Age缺失约177条占比接近20%Cabin缺失约687条占比接近77%Embarked缺失仅2条这三个字段的缺失程度完全不同处理方式也不一样。Age可以填充可以建模预测Cabin缺失太多强行填充反而容易引入噪声更合理的做法是把它拆成一个“是否有船舱记录”的特征。Embarked只有两条缺失直接用众数填充就够了。这里我特别想说一句很多人一上来就dropna把所有缺失行删掉如果只是做练习倒也行但会丢掉大量有效样本。泰坦尼克号数据本来就是小样本891行其实很珍贵合理处理缺失值比粗暴删除更有价值。3.3 用图表快速感知生存率分布数据初步看完之后画几张图比看一堆数字更直观。我通常会先画一张全局的生存率分布再按几个关键特征分组看差异。sns.countplot(xSurvived, datatrain) plt.show() sns.barplot(xPclass, ySurvived, datatrain) plt.show() sns.barplot(xSex, ySurvived, datatrain) plt.show()从这几张图能看到非常明显的信息头等舱生存率显著高于三等舱女性生存率远高于男性。这些结果和历史上“妇女儿童优先”以及“头等舱距离救生艇更近”的客观情况是吻合的。不要小看这一步。通过可视化建立直觉能帮你在特征工程阶段作出更合理的判断。比如你发现Sex对生存率影响很大那在建模时就可以优先考虑性别相关的特征组合。4. 特征工程从原始字段到有效特征4.1 缺失值填充的实操策略特征工程是整个项目里最花心思的部分也是不同人做出来的模型效果差距最大的环节。先处理缺失值。Age这列我实测下来比较稳的方法是按Sex和Pclass分组后取中位数填充。原因是不同性别和不同舱位的乘客年龄分布差异明显如果用全量均值填充会掩盖这层信息。train[Age] train.groupby([Sex, Pclass])[Age].transform(lambda x: x.fillna(x.median())) test[Age] test.groupby([Sex, Pclass])[Age].transform(lambda x: x.fillna(x.median()))Embarked用众数填充train[Embarked] train[Embarked].fillna(train[Embarked].mode()[0]) test[Embarked] test[Embarked].fillna(test[Embarked].mode()[0])Cabin这列我把缺失标记为0有值标记为1生成一个新特征train[Has_Cabin] train[Cabin].notnull().astype(int) test[Has_Cabin] test[Cabin].notnull().astype(int)实测下来Has_Cabin这个特征对模型有一定的区分度。原因可能是有船舱记录的乘客和没记录乘客在购票渠道、登船批次上存在差异这种差异间接反映了生存概率。4.2 构造新特征称呼、家庭规模、是否独行泰坦尼克号数据里有一个经常被忽略但信息量很大的字段Name。名字本身没有意义但从名字里提取称谓Title非常有用。train[Title] train[Name].str.extract( ([A-Za-z])\\., expandFalse) test[Title] test[Name].str.extract( ([A-Za-z])\\., expandFalse)观察一下出现频率能看到Mr、Mrs、Miss、Master占绝大多数还有少量Dr、Rev、Lady、Countess等。Master这个称谓比较特殊通常指未成年男孩。这就意味着Title不仅反映了身份还能侧面推断年龄和性别是一个多维度的好特征。我一般会把低频称谓合并成一个“其他”类别减少类别数量rare_titles [Lady, Countess, Capt, Col, Don, Dr, Major, Rev, Sir, Jonkheer, Dona] train[Title] train[Title].replace(rare_titles, Rare) test[Title] test[Title].replace(rare_titles, Rare)家庭规模是另一个经典构造特征。SibSp和Parch虽然单独列出来了但它们组合起来能更好表达“一个乘客在船上有多少个家人”train[FamilySize] train[SibSp] train[Parch] 1 test[FamilySize] test[SibSp] test[Parch] 1再从FamilySize派生一个二元特征IsAlone表示是否独行train[IsAlone] (train[FamilySize] 1).astype(int) test[IsAlone] (test[FamilySize] 1).astype(int)这个特征在数据里的区分度很明显独自乘船的人生存率偏低和家人一起的生存率相对高。原因也不难理解独行乘客往往是三等舱的年轻男性本身生存率就不高。4.3 类别特征编码与数值特征标准化模型只能吃数字所以Sex、Embarked、Title这些文本特征必须转成数值形式。我倾向于用pandas的get_dummies做独热编码features [Pclass, Sex, Age, FamilySize, IsAlone, Has_Cabin, Fare, Embarked, Title] train pd.get_dummies(train[features [Survived]], columns[Sex, Embarked, Title]) test pd.get_dummies(test[features], columns[Sex, Embarked, Title])独热编码的原理说起来很简单把一个多类别字段拆成多个0/1字段。比如Embarked变成Embarked_C、Embarked_Q、Embarked_S三列某一行如果乘客在C港口登船那Embarked_C就是1其余两个是0。关于Faretrain和test里可能会有少量缺失值保险起见统一填充中位数test[Fare] test[Fare].fillna(train[Fare].median())数值标准化这一步我实测下来对逻辑回归这类线性模型有较大帮助对树模型影响不大。如果你后面要用逻辑回归建议先把Age和Fare做标准化如果只用随机森林或XGBoost这一步可以省略。4.4 特征选择与相关性检查特征做完以后不要急着全丢进模型。先用corr()看下特征和Survived的相关性train.corr()[Survived].sort_values(ascendingFalse)这段代码会输出一个相关系数从高到低的排序。我在实际项目中看到的结果一般是Sex_female、Title_Mrs、Pclass这些和Survived相关性较高而PassengerId基本没有相关性。这里还有一个常见的坑train和test经过get_dummies后列名可能不完全一致。比如某个类别只出现在train里但没出现在test里或者反过来。为了避免模型训练和预测时维度不匹配建议加一行对齐操作train, test train.align(test, joinleft, axis1)align之后多出来的列会自动补0保证两边特征维度一致。这一步看起来不起眼但能帮你避免很多莫名其妙的报错。5. 模型训练与评估让预测结果可解释5.1 交叉验证与评估指标设定泰坦尼克号是一个二分类问题评估指标最常用的是Accuracy准确率但只看Accuracy不够我建议同时看混淆矩阵和ROC-AUC。为什么不能只看Accuracy因为类别分布本身存在偏差。泰坦尼克号数据里Survived0和Survived1的比例大约是62%对38%。如果你写一个模型无脑预测全部为0准确率也有62%但这个模型没有任何实际价值。ROC-AUC关注的是模型在不同阈值下的区分能力更能反映真实水平。交叉验证方面我用StratifiedKFold分层K折交叉验证保证每一折训练集和验证集里Survived比例与整体一致。5折比较常用from sklearn.model_selection import StratifiedKFold skf StratifiedKFold(n_splits5, shuffleTrue, random_state42)5.2 逻辑回归快速建立基线建模第一步先跑一个逻辑回归作为基线。逻辑回归最大的优点是简单、可解释性强能快速验证特征工程是否有效。from sklearn.linear_model import LogisticRegression from sklearn.model_selection import cross_val_score X train.drop(columns[Survived]) y train[Survived] lr LogisticRegression(max_iter1000) scores cross_val_score(lr, X, y, cvskf, scoringaccuracy) print(LR CV Accuracy: {:.4f} ± {:.4f}.format(scores.mean(), scores.std()))在我常用的一组特征组合下逻辑回归5折交叉验证准确率大约能到80%到82%。这个数字算是一个很合理的基线。如果基线准确率连75%都不到多半是特征工程有问题先检查有没有引入太多噪声特征或者有没有忘记处理缺失值。5.3 随机森林提升精度的常用手段逻辑回归之后我会用随机森林对比一下效果。随机森林对特征交互的捕捉能力更强而且对异常值不敏感在表格数据上表现稳定。from sklearn.ensemble import RandomForestClassifier rf RandomForestClassifier(n_estimators200, random_state42, max_depth5) scores_rf cross_val_score(rf, X, y, cvskf, scoringaccuracy) print(RF CV Accuracy: {:.4f} ± {:.4f}.format(scores_rf.mean(), scores_rf.std()))通过调参随机森林的交叉验证准确率一般能比逻辑回归高1到2个百分点大约在82%到84%区间。这里我特别强调一下max_depth参数很多人直接用默认值树的深度太大容易过拟合。泰坦尼克号数据量不大把max_depth限制在4到6n_estimators在200到500之间实测效果最好。5.4 用GridSearchCV做参数调优手工试参数效率低我一般用GridSearchCV做一个简单的网格搜索同时找到Randforest的最优参数组合from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [200, 400], max_depth: [4, 6, 8], min_samples_split: [2, 5], min_samples_leaf: [1, 2] } grid GridSearchCV(RandomForestClassifier(random_state42), param_grid, cvskf, scoringaccuracy, n_jobs-1) grid.fit(X, y) print(grid.best_params_) print(grid.best_score_)网格搜索的原理就是把参数组合逐一跑一遍选出效果最好的组合。看着简单但要注意n_jobs-1参数否则会利用全部CPU核心跑起来更快。我自己的经验是随机森林的n_estimators从200升到400提升幅度很小反而是max_depth和min_samples_leaf对结果影响更大。6. 从零到提交完整预测流程串联6.1 将训练流程封装成函数前面的步骤如果一步步执行没问题但从工程化角度来讲为了实际预测和提交最好把整个流程封装成函数避免每次手动复制代码。我来演示一个可运行的简化版本import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import StratifiedKFold, cross_val_score RANDOM_STATE 42 def load_data(train_path, test_path): train pd.read_csv(train_path) test pd.read_csv(test_path) return train, test def process_data(train, test): # 缺失值处理 train[Age] train.groupby([Sex, Pclass])[Age].transform(lambda x: x.fillna(x.median())) test[Age] test.groupby([Sex, Pclass])[Age].transform(lambda x: x.fillna(x.median())) train[Embarked] train[Embarked].fillna(train[Embarked].mode()[0]) test[Embarked] test[Embarked].fillna(test[Embarked].mode()[0]) test[Fare] test[Fare].fillna(train[Fare].median()) # 构造特征 for df in (train, test): df[Has_Cabin] df[Cabin].notnull().astype(int) df[Title] df[Name].str.extract( ([A-Za-z])\\., expandFalse) df[FamilySize] df[SibSp] df[Parch] 1 df[IsAlone] (df[FamilySize] 1).astype(int) train[Title] train[Title].replace([Lady, Countess, Capt, Col, Don, Dr, Major, Rev, Sir, Jonkheer, Dona], Rare) test[Title] test[Title].replace([Lady, Countess, Capt, Col, Don, Dr, Major, Rev, Sir, Jonkheer, Dona], Rare) features [Pclass, Sex, Age, FamilySize, IsAlone, Has_Cabin, Fare, Embarked, Title] X pd.get_dummies(train[features], columns[Sex, Embarked, Title]) y train[Survived] X_test pd.get_dummies(test[features], columns[Sex, Embarked, Title]) X, X_test X.align(X_test, joinleft, axis1) X_test X_test.fillna(0) return X, y, X_test def train_and_predict(train_path, test_path, output_path): train, test load_data(train_path, test_path) X, y, X_test process_data(train, test) skf StratifiedKFold(n_splits5, shuffleTrue, random_stateRANDOM_STATE) model RandomForestClassifier(n_estimators300, max_depth6, min_samples_split5, min_samples_leaf1, random_stateRANDOM_STATE) scores cross_val_score(model, X, y, cvskf, scoringaccuracy) print(CV Accuracy: {:.4f} ± {:.4f}.format(scores.mean(), scores.std())) model.fit(X, y) test[Survived] model.predict(X_test) test[[PassengerId, Survived]].to_csv(output_path, indexFalse) if __name__ __main__: train_and_predict(train.csv, test.csv, submission.csv)这段代码把前面所有关键步骤整合了。实际操作中如果train和test的字段分布差异较大align后可能出现全为0的列这时可以手动删除全0特征避免给模型带来噪声。6.2 生成test.csv预测结果并导出生成提交文件后最好先检查一下输出文件的内容sub pd.read_csv(submission.csv) print(sub.head()) print(sub[Survived].value_counts())value_counts会显示预测结果中0和1的分布。一个合理的结果应该是0和1都有一定的比例如果你发现预测出来全部是0说明模型有问题很可能处在了模型拟合失败或特征处理失误。如果不想自己去验证可以直接提交到Kaggle平台看分数。7. 踩坑实录解决我遇到过的高频问题7.1 解压与文件损坏zip相关报错这是最常遇到的一类问题也是很多新手第一个崩溃点。报错“file is not a zip file”先确认文件真实格式用file命令或Python的zipfile检测不要相信后缀名。报错“could not find eocd”说明zip文件末尾的中心目录损坏了。优先重新下载如果下载多次都这样考虑源文件本身问题。下载到一半中断浏览器或下载工具可能生成了一个临时文件然后重命名了注意检查文件大小和源文件是否一致。用Python处理时遇到“BadZipFile”同样优先看文件完整性而不是急于修改代码。7.2 环境依赖与版本兼容pandas和numpy版本不匹配时可能出现某些函数找不到或者报错ModuleNotFoundError。建议把依赖库装在同一个虚拟环境里不要全局混装。如果你拿到的是旧代码里面用了类似df.append这种旧接口新版pandas已经移除了这个方法。可以直接改成pd.concat。scikit-learn的接口变化也比较多比如某些模型的参数名改了版本跨太大直接跑的话会报TypeError。7.3 数据读写的中文路径与编码这个问题主要出现在Windows系统。如果文件路径含有中文pandas可能读取失败。我一般把项目文件夹放在纯英文路径下比如D:\projects\titanic从根上规避。如果编码报错读取csv的时候指定编码方式df pd.read_csv(train.csv, encodingutf-8)老版本的数据也可能是GBK编码可以换成encodinggbk测试。7.4 模型效果异常排查交叉验证分数很高但测试集表现差基本可以断定是过拟合。减少max_depth、增加min_samples_leaf、减少特征数量都可以缓解。交叉验证分数很低先检查特征工程尤其要看是否有大量全0列或者泄漏了未来信息的列。Test集字段和Train集不一致使用train.align(test, joinleft, axis1)对齐特征这是最稳妥的解法。预测结果全部是同一类别检查是否在fit之前搞混了X和y或者y的值域是否有问题。8. 基于个人经验的扩展建议这个项目做完以后如果你还有余力我建议别急着做下一个数据集先把已经写完的代码回头重构一遍。我自己的体会是第一次跑通大概只是记住了流程第二次再写的时候才会真正理解每一步为什么这么做。可以尝试的扩展方向有几个。第一用同样的特征工程跑一下更复杂的模型比如LightGBM、XGBoost对比效果。第二尝试对Age做分段处理而不是直接数值输入有些情况下分类化处理对模型更友好。第三做一下特征重要性分析看看随机森林认为哪些特征最重要和你的业务直觉是否一致。另外当年我自己反复调参后交叉验证分数卡在83%左右一直难以继续提升。后来发现突破口在特征工程而不是模型参数把Cabin拆成甲板层号再次提升了一点。这个经验你可以参考当模型调参收益越来越小时回到特征层面找新的信息量往往比继续堆参数更有效。最后分享一个实用技巧任何时候改完代码都要重新跑一遍从数据读取到交叉验证的完整流程确认没有引入隐藏bug。这个习惯能帮你节省大量排查时间尤其当数据量变大、步骤变多以后。泰坦尼克号这个项目虽然小但它包含的每个环节都是数据建模的正规打法认真走一遍后面的迁移学习就不难了。本文还有配套的精品资源点击获取
返回列表