1. 项目背景与核心目标
泰坦尼克号生存预测是机器学习领域最经典的入门项目之一,它基于1912年泰坦尼克号沉船事件中的乘客数据,要求我们构建模型预测每位乘客的生存概率。这个项目之所以成为机器学习教学的"Hello World",是因为它完美涵盖了数据科学项目的完整流程:
- 数据获取与清洗(缺失值/异常值处理)
- 探索性数据分析(EDA)
- 特征工程(特征提取/转换/选择)
- 模型选择与训练
- 模型评估与优化
提示:虽然数据集规模不大(约891条训练数据),但特征维度丰富(12个原始特征),非常适合练习特征工程技巧。
2. 数据理解与预处理
2.1 数据集字段解析
原始数据包含以下关键特征:
| 字段名 | 类型 | 说明 | 缺失比例 |
|---|---|---|---|
| PassengerId | int | 乘客ID | 0% |
| Survived | int | 生存标签(0=否,1=是) | 0% |
| Pclass | int | 舱位等级(1/2/3) | 0% |
| Name | string | 乘客姓名 | 0% |
| Sex | string | 性别 | 0% |
| Age | float | 年龄 | 19.87% |
| SibSp | int | 同船兄弟姐妹/配偶数量 | 0% |
| Parch | int | 同船父母/子女数量 | 0% |
| Ticket | string | 船票编号 | 0% |
| Fare | float | 船票价格 | 0% |
| Cabin | string | 船舱编号 | 77.10% |
| Embarked | string | 登船港口(C/Q/S) | 0.22% |
2.2 数据清洗实战
缺失值处理方案:
Age:采用"Title+性别+Pclass"分组中位数填充
# 从Name提取Title(Mr/Miss/Mrs等) df['Title'] = df.Name.str.extract(' ([A-Za-z]+)\.', expand=False) # 按分组计算中位数 age_median = df.groupby(['Title','Sex','Pclass'])['Age'].median() # 填充缺失值 df['Age'] = df.apply(lambda x: age_median[x['Title'],x['Sex'],x['Pclass']] if pd.isnull(x['Age']) else x['Age'], axis=1)Cabin:由于缺失率过高,直接删除该列,但先提取首字母作为新特征
df['Cabin_Letter'] = df['Cabin'].str[0] # 提取船舱首字母 df = df.drop('Cabin', axis=1)Embarked:仅2条缺失,用众数填充
df['Embarked'].fillna(df['Embarked'].mode()[0], inplace=True)
3. 特征工程深度解析
3.1 特征构造技巧
姓名特征挖掘:
- 提取称呼(Title):反映社会地位
title_mapping = { 'Capt': 'Officer', 'Col': 'Officer', 'Major': 'Officer', 'Dr': 'Officer', 'Rev': 'Officer', 'Jonkheer': 'Royalty', 'Don': 'Royalty', 'Sir': 'Royalty', 'Lady': 'Royalty', 'Countess': 'Royalty', 'Dona': 'Royalty', 'Mme': 'Mrs', 'Ms': 'Mrs', 'Mrs': 'Mrs', 'Miss': 'Miss', 'Mlle': 'Miss', 'Master': 'Master', 'Mr': 'Mr' } df['Title'] = df['Title'].map(title_mapping)家庭特征组合:
- 家庭规模 = SibSp + Parch + 1
- 是否独自旅行 = (家庭规模 == 1)
df['FamilySize'] = df['SibSp'] + df['Parch'] + 1 df['IsAlone'] = (df['FamilySize'] == 1).astype(int)票价特征优化:
- 人均票价 = Fare / FamilySize
df['FarePerPerson'] = df['Fare'] / df['FamilySize']
3.2 特征编码方案
有序类别特征(Pclass)直接保留数值
名义类别特征(Sex/Embarked/Title)使用独热编码:
df = pd.get_dummies(df, columns=['Sex','Embarked','Title'], drop_first=True)连续特征(Age/Fare)分箱处理:
df['AgeBin'] = pd.qcut(df['Age'], q=5, labels=False) df['FareBin'] = pd.qcut(df['Fare'], q=4, labels=False)
4. 模型构建与优化
4.1 基准模型对比
我们测试5种经典算法(使用5折交叉验证):
| 模型 | 平均准确率 | 训练时间(s) |
|---|---|---|
| Logistic回归 | 0.821 | 0.12 |
| 随机森林 | 0.830 | 0.45 |
| 梯度提升树(XGBoost) | 0.836 | 0.78 |
| SVM(rbf核) | 0.828 | 1.23 |
| KNN(k=5) | 0.798 | 0.34 |
注意:XGBoost表现最佳,但随机森林与之接近且训练更快,适合作为基线模型。
4.2 随机森林调优实战
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV param_grid = { 'n_estimators': [100, 200, 300], 'max_depth': [3, 5, 7, None], 'min_samples_split': [2, 5, 10], 'min_samples_leaf': [1, 2, 4] } rf = RandomForestClassifier(random_state=42) grid_search = GridSearchCV(rf, param_grid, cv=5, scoring='accuracy', n_jobs=-1) grid_search.fit(X_train, y_train) print(f"最佳参数:{grid_search.best_params_}") print(f"最佳得分:{grid_search.best_score_:.3f}")调优后特征重要性分析:
Age 0.214 Fare 0.183 Sex_male 0.162 Pclass 0.141 IsAlone 0.089 FamilySize 0.072 Embarked_Q 0.058 Embarked_S 0.051 Title_Mr 0.048 SibSp 0.0425. 项目进阶技巧
5.1 集成模型方案
结合XGBoost和随机森林的Stacking集成:
from sklearn.ensemble import StackingClassifier from xgboost import XGBClassifier base_models = [ ('rf', RandomForestClassifier(n_estimators=200, max_depth=5, random_state=42)), ('xgb', XGBClassifier(n_estimators=100, learning_rate=0.1, random_state=42)) ] stacking = StackingClassifier( estimators=base_models, final_estimator=LogisticRegression(), cv=5 ) stacking.fit(X_train, y_train)5.2 常见问题排查
准确率卡在0.78-0.82无法提升
- 检查特征相关性:删除冗余特征(如同时存在FamilySize和SibSp+Parch)
- 尝试非线性特征组合(如Age*Pclass)
过拟合问题
- 增加早停机制(early_stopping_rounds)
- 添加正则化参数(XGBoost的reg_alpha/reg_lambda)
类别不平衡处理
- 使用class_weight参数(sklearn)或scale_pos_weight(XGBoost)
- 尝试过采样(SMOTE)或欠采样
6. 项目扩展方向
模型解释性增强
- 使用SHAP值分析个体预测
import shap explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X_test) shap.summary_plot(shap_values, X_test)部署为Web应用
- 使用Flask构建预测API
- 前端展示预测结果和特征影响
数据增强实验
- 生成合成数据(使用CTGAN等生成模型)
- 半监督学习(利用测试集数据)
这个项目最值得关注的是特征工程环节——好的特征设计往往比模型选择影响更大。在实际操作中,我通常会先花70%时间在EDA和特征工程上,这比盲目调参效果提升更明显。另外,建议保存每个版本的预处理流水线(使用sklearn Pipeline),方便后续复现和部署。