【机器学习】泰坦尼克号生存预测 – 从单模型到多模型对比分析
引言
泰坦尼克号沉没是历史上最著名的海难之一,也是机器学习领域一个经典的入门级预测项目。本项目通过对乘客数据进行分析和建模,预测在这场灾难中乘客的生存概率。
在这个项目中,我们将:
探索和分析泰坦尼克号乘客数据集使用随机森林算法构建单模型进行生存预测实现五种不同机器学习算法的对比分析可视化展示预测结果和特征重要性生成最终的预测提交结果
通过这个项目,我们可以深入理解数据预处理、特征工程、模型选择和评估等机器学习的核心步骤,同时也能体会到不同算法在同一问题上的表现差异。
技术栈
Python 3.9pandas 1.2.5:数据处理和分析numpy 1.20.3:科学计算scikit-learn 0.24.2:机器学习算法和评估工具matplotlib 3.4.2:数据可视化seaborn:高级统计图形绘制
数据探索与分析
数据集概览
我们使用的泰坦尼克号数据集包含两个主要文件:
train.csv:包含891条记录,用于模型训练,包含生存标签test.csv:包含418条记录,用于最终预测,不包含生存标签
数据结构
训练集数据包含以下字段:
:乘客ID
PassengerId:生存标签(0=死亡,1=生存)
Survived:乘客等级(1=一等舱,2=二等舱,3=三等舱)
Pclass:乘客姓名
Name:性别
Sex:年龄
Age:船上兄弟姐妹/配偶数量
SibSp:船上父母/子女数量
Parch:船票号码
Ticket:票价
Fare:客舱号码
Cabin:登船港口(C=瑟堡,Q=皇后镇,S=南安普顿)
Embarked
基本统计分析
通过对训练集的分析,我们得到了一些重要的统计信息:
生存率:在训练集中,约有38.4%的乘客存活下来性别分布:男性约占65%,女性约占35%年龄分布:年龄范围从0.42岁到80岁,平均年龄约为29.7岁乘客等级:三等舱乘客最多,约占55%;一等舱约占24%;二等舱约占21%
缺失值分析
数据中存在一些缺失值需要处理:
Age:约177条记录缺失年龄信息Cabin:大量记录缺失客舱信息(约77%)Embarked:只有2条记录缺失登船港口信息
这些缺失值将在数据预处理阶段进行处理。
数据可视化初步分析
从初步的可视化分析中,我们发现了几个关键的生存模式:
性别与生存关系:女性的生存率显著高于男性(这就是著名的”妇女优先”原则)乘客等级与生存关系:一等舱乘客的生存率最高,其次是二等舱,三等舱最低年龄与生存关系:儿童的生存率相对较高
这些观察结果为我们的特征工程提供了重要的指导。
单模型实现:随机森林
在这一部分,我们将使用随机森林算法构建单模型来预测乘客的生存概率。随机森林是一种集成学习方法,通过构建多个决策树并将它们的预测结果进行组合,通常能够提供更好的性能和泛化能力。
数据预处理和特征工程
数据预处理和特征工程是机器学习中至关重要的步骤。我们实现了以下预处理和特征工程方法:
# 特征工程:从姓名中提取头衔
def extract_title(name):
import re
title_search = re.search(' ([A-Za-z]+).', name)
if title_search:
return title_search.group(1)
return ""
train_data['Title'] = train_data['Name'].apply(extract_title)
test_data['Title'] = test_data['Name'].apply(extract_title)
# 将稀有头衔归类
rare_titles = ['Capt', 'Col', 'Countess', 'Don', 'Dr', 'Jonkheer', 'Lady', 'Major', 'Rev', 'Sir']
train_data['Title'] = train_data['Title'].replace(rare_titles, 'Rare')
test_data['Title'] = test_data['Title'].replace(rare_titles, 'Rare')
# 规范化常见头衔
train_data['Title'] = train_data['Title'].replace('Mlle', 'Miss')
train_data['Title'] = train_data['Title'].replace('Ms', 'Miss')
train_data['Title'] = train_data['Title'].replace('Mme', 'Mrs')
我们还创建了一些新的特征:
# 计算家庭大小
train_data['FamilySize'] = train_data['SibSp'] + train_data['Parch'] + 1
test_data['FamilySize'] = test_data['SibSp'] + test_data['Parch'] + 1
# 创建家庭大小类别
train_data['IsAlone'] = 1 # 初始化为1,表示单独
train_data.loc[train_data['FamilySize'] > 1, 'IsAlone'] = 0 # 如果家庭大小大于1,则不是单独
test_data['IsAlone'] = 1
test_data.loc[test_data['FamilySize'] > 1, 'IsAlone'] = 0
对于缺失值的处理,我们采用了不同的策略:
# 填充Embarked的缺失值(用众数)
train_data['Embarked'] = train_data['Embarked'].fillna(train_data['Embarked'].mode()[0])
# 填充Fare的缺失值(用平均值)
test_data['Fare'] = test_data['Fare'].fillna(test_data['Fare'].mean())
# 基于年龄分组的平均生存率来填充年龄
age_medians = train_data.groupby(['Sex', 'Pclass', 'Title'])['Age'].transform('median')
train_data['Age'] = train_data['Age'].fillna(age_medians)
模型构建和训练
我们使用scikit-learn的Pipeline和ColumnTransformer来构建完整的数据处理和模型训练流程:
# 定义数值特征和分类特征的预处理步骤
numerical_features = ['Age', 'Fare', 'SibSp', 'Parch', 'FamilySize']
categorical_features = ['Pclass', 'Sex', 'Embarked', 'Title', 'IsAlone']
numerical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
# 组合预处理步骤
preprocessor = ColumnTransformer(
transformers=[
('num', numerical_transformer, numerical_features),
('cat', categorical_transformer, categorical_features)
])
# 构建完整的管道,包括预处理和模型
model_pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', RandomForestClassifier(n_estimators=100, random_state=42))
])
然后我们将数据集分割为训练集和验证集,训练模型并在验证集上评估性能:
# 分割训练集用于验证
X_train_split, X_val, y_train_split, y_val = train_test_split(
X_train, y_train, test_size=0.2, random_state=42
)
# 训练模型
model_pipeline.fit(X_train_split, y_train_split)
# 在验证集上评估模型
y_val_pred = model_pipeline.predict(X_val)
accuracy = accuracy_score(y_val, y_val_pred)
print(f"验证集准确率: {accuracy:.4f}")
特征重要性分析
随机森林算法能够提供特征重要性的评估,这对于理解哪些因素对生存预测最关键非常有帮助:
# 获取分类器的特征重要性
importances = model_pipeline.named_steps['classifier'].feature_importances_
# 创建特征重要性DataFrame
importance_df = pd.DataFrame({
'Feature': all_feature_names,
'Importance': importances
}).sort_values('Importance', ascending=False)
print("
特征重要性(前10个):")
print(importance_df.head(10))
从分析结果来看,票价(Fare)、年龄(Age)和性别(Sex)是影响生存预测最重要的因素,这与我们之前的探索性分析结果一致。
预测结果生成
最后,我们使用训练好的模型对测试集进行预测,并生成提交文件:
# 预测
predictions = model.predict(X_test)
# 创建提交文件
submission = pd.DataFrame({
'PassengerId': test_data['PassengerId'],
'Survived': predictions
})
submission_file = 'titanic_submission.csv'
submission.to_csv(submission_file, index=False)
随机森林模型在验证集上达到了约85.47%的准确率,这是一个相当不错的结果。
多模型对比分析
在单模型实现的基础上,我们进一步进行了多种机器学习算法的对比分析,以找出在泰坦尼克号生存预测任务上表现最佳的算法。
实现的算法集合
我们选择了以下五种常见的分类算法进行对比:
随机森林(Random Forest):集成学习方法,通过构建多个决策树并投票的方式进行预测逻辑回归(Logistic Regression):线性分类模型,适合二分类问题支持向量机(Support Vector Machine):寻找最优超平面进行分类决策树(Decision Tree):基于特征划分的树状模型梯度提升树(Gradient Boosting):迭代式集成学习方法,每次训练修正上一次的错误
这些算法在代码中的实现如下:
# 定义要比较的算法
algorithms = {
'随机森林': RandomForestClassifier(n_estimators=100, random_state=42),
'逻辑回归': LogisticRegression(random_state=42, max_iter=1000),
'支持向量机': SVC(probability=True, random_state=42),
'决策树': DecisionTreeClassifier(random_state=42),
'梯度提升树': GradientBoostingClassifier(random_state=42)
}
统一的评估框架
为了公平地比较不同算法,我们建立了统一的评估框架,包括:
相同的预处理流程:所有算法使用完全相同的数据预处理和特征工程步骤5折交叉验证:使用k折交叉验证减少过拟合风险,更准确评估模型泛化能力统一的评估指标:主要使用准确率(accuracy)作为评估指标
代码实现如下:
def compare_algorithms(X_train, y_train, preprocessor):
"""比较多种机器学习算法的性能"""
# 存储每个算法的评估结果
results = {}
best_algorithm = None
best_accuracy = 0
print("
===== 多种算法性能对比 =====")
for name, algorithm in algorithms.items():
print(f"
{name} 算法评估:")
# 创建完整的管道
pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', algorithm)
])
# 使用5折交叉验证
cv_scores = cross_val_score(pipeline, X_train, y_train, cv=5, scoring='accuracy')
# 计算平均准确率和标准差
mean_accuracy = cv_scores.mean()
std_accuracy = cv_scores.std()
# 记录结果
results[name] = {
'pipeline': pipeline,
'cv_scores': cv_scores,
'mean_accuracy': mean_accuracy,
'std_accuracy': std_accuracy
}
# 打印结果
print(f"交叉验证准确率: {cv_scores}")
print(f"平均准确率: {mean_accuracy:.4f} ± {std_accuracy:.4f}")
# 更新最佳算法
if mean_accuracy > best_accuracy:
best_accuracy = mean_accuracy
best_algorithm = name
print(f"
最佳算法: {best_algorithm},平均准确率: {best_accuracy:.4f}")
return results, best_algorithm
算法性能对比结果
经过评估,各算法的性能如下(基于5折交叉验证):
| 算法 | 平均准确率 | 标准差 |
|---|---|---|
| 随机森林 | 0.8396 | 0.0323 |
| 逻辑回归 | 0.8215 | 0.0263 |
| 支持向量机 | 0.8292 | 0.0281 |
| 决策树 | 0.7994 | 0.0236 |
| 梯度提升树 | 0.8376 | 0.0301 |
从结果可以看出:
随机森林和梯度提升树表现最佳,平均准确率均超过83%支持向量机次之,准确率约为82.92%逻辑回归紧随其后,准确率约为82.15%决策树表现相对较弱,但准确率也达到了79.94%
算法性能可视化
为了更直观地比较各算法的性能差异,我们创建了两种可视化图表:
算法对比柱状图:展示各算法的平均准确率和标准差算法性能分布箱线图:展示各算法在5次交叉验证中的性能分布
柱状图实现代码:
def visualize_comparison(results):
"""可视化不同算法的性能对比"""
# 准备数据进行可视化
names = list(results.keys())
means = [results[name]['mean_accuracy'] for name in names]
stds = [results[name]['std_accuracy'] for name in names]
# 创建柱状图
plt.figure(figsize=(12, 6))
bars = plt.bar(names, means, yerr=stds, capsize=5, color=['blue', 'green', 'red', 'orange', 'purple'])
# 添加标题和标签
plt.title('不同机器学习算法性能对比')
plt.xlabel('算法')
plt.ylabel('准确率')
plt.ylim(0.7, 0.9) # 设置y轴范围,使差异更明显
# 在柱状图上添加数值标签
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2., height + 0.01,
f'{height:.4f}', ha='center', va='bottom')
# 保存图表
plt.tight_layout()
plt.savefig('algorithm_comparison.png')
最佳算法详细评估
随机森林算法表现最佳,我们对其进行了更详细的评估,包括:
混淆矩阵:分析预测错误的类型和数量分类报告:详细的精确率、召回率和F1值
混淆矩阵的实现:
# 绘制混淆矩阵
plt.figure(figsize=(8, 6))
cm = confusion_matrix(y_val, y_val_pred)
plt.imshow(cm, interpolation='nearest', cmap='Blues')
plt.title('最佳算法混淆矩阵')
plt.colorbar()
classes = ['死亡', '存活']
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes)
plt.yticks(tick_marks, classes)
通过详细评估,我们可以更全面地了解模型的优缺点,为后续优化提供方向。
结果可视化与分析
在机器学习项目中,可视化是理解数据和模型表现的强大工具。在本项目中,我们生成了多种可视化图表,帮助我们更深入地理解数据特征、模型性能和预测结果。
模型性能可视化
1. 算法对比柱状图 (algorithm_comparison.png)
这个柱状图直观地展示了五种不同机器学习算法的平均准确率和标准差。从图中可以清晰地看到:

随机森林和梯度提升树的柱子最高,表明它们是表现最好的两种算法每种算法的误差线(error bar)显示了算法在5折交叉验证中的性能波动所有算法的准确率都超过了79%,说明我们的数据特征工程是有效的
2. 算法性能分布箱线图 (algorithm_boxplot.png)
箱线图提供了更详细的算法性能分布信息:

箱子的中间线表示中位数准确率箱子的上下边界表示25%和75%分位数箱子外的胡须展示了数据的完整范围异常值(如果有的话)用点表示
从箱线图可以看出,随机森林和梯度提升树不仅平均准确率高,而且性能相对稳定,而决策树的性能分布范围较大,说明其稳定性相对较差。
3. 最佳算法混淆矩阵 (best_algorithm_confusion_matrix.png)
混淆矩阵是评估分类模型性能的重要工具,可以帮助我们分析:
真正例(TP):正确预测为存活的乘客数假负例(FN):错误预测为死亡的存活乘客数假正例(FP):错误预测为存活的死亡乘客数真负例(TN):正确预测为死亡的乘客数

通过分析混淆矩阵,我们可以:
计算精确率(precision)、召回率(recall)和F1分数等更全面的评估指标识别模型容易混淆的类别,找出改进方向理解模型在不同类别上的表现差异
特征分析可视化
4. 特征重要性图 (feature_importance.png)
对于随机森林和梯度提升树这类模型,我们可以分析每个特征对预测结果的贡献程度:

图表按重要性降序排列展示了所有特征特征重要性得分表示该特征在模型决策过程中的影响力从图中可以看出,票价(Fare)、年龄(Age)和性别(Sex)是影响生存预测最重要的三个特征这与我们在数据探索阶段的发现一致,也符合历史事实(泰坦尼克号灾难中”妇女和儿童优先”的救援策略)
5. 生存率分析图
我们还创建了多种生存率分析图表,从不同维度展示了乘客生存的统计规律:

按乘客等级的生存率 (survival_by_class.png):清晰地展示了不同社会阶层乘客的生存差异,头等舱乘客生存率显著高于其他舱位,这反映了灾难中的社会不平等现象

按性别的生存率 (survival_by_sex.png):直观地显示女性生存率远高于男性,这与”妇女优先”的救援策略一致
可视化代码示例
以下是我们生成特征重要性图的代码示例:
# 绘制特征重要性图
def plot_feature_importance(model, feature_names):
importances = model.feature_importances_
indices = np.argsort(importances)[::-1]
plt.figure(figsize=(12, 6))
plt.title('特征重要性分析')
plt.bar(range(len(importances)), importances[indices])
plt.xticks(range(len(importances)), [feature_names[i] for i in indices], rotation=90)
plt.tight_layout()
plt.savefig('feature_importance.png')
plt.show()
以下是生存率可视化的代码示例:
# 绘制按乘客等级的生存率
def plot_survival_by_class(data):
survival_by_class = data.groupby('Pclass')['Survived'].mean() * 100
plt.figure(figsize=(8, 6))
survival_by_class.plot(kind='bar', color=['red', 'orange', 'green'])
plt.title('不同乘客等级的生存率')
plt.xlabel('乘客等级')
plt.ylabel('生存率 (%)')
plt.xticks(rotation=0)
plt.ylim(0, 100)
# 添加数值标签
for i, v in enumerate(survival_by_class):
plt.text(i, v + 2, f'{v:.1f}%', ha='center')
plt.tight_layout()
plt.savefig('survival_by_class.png')
可视化结果的业务洞见
通过这些可视化图表,我们不仅可以评估模型性能,还能获得重要的业务洞见:
特征重要性分析帮助我们理解哪些因素对生存预测最关键,这对于理解灾难中的生存规律具有重要意义
算法对比可视化帮助我们选择最佳的预测模型,为实际应用提供指导
生存率分析图揭示了泰坦尼克号灾难中的社会分层和救援策略对生存率的影响
混淆矩阵分析帮助我们了解模型的优缺点,为模型改进提供方向
总体而言,这些可视化图表大大增强了我们对数据和模型的理解,使我们能够更全面地分析问题和评估解决方案。
总结与展望
在本文中,我们完成了一个完整的机器学习项目流程,从数据探索、特征工程到模型构建、评估和可视化。以下是我们的主要成果和发现:
项目总结
数据理解与预处理:我们成功处理了包含缺失值的数据集,通过特征工程创建了多个有价值的新特征,如Title、FamilySize和IsAlone等。
单模型实现:使用随机森林算法构建了基准模型,在验证集上达到了85.47%的准确率。
多模型对比分析:比较了五种不同的机器学习算法,发现随机森林和梯度提升树表现最佳,平均准确率均超过83%。
可视化分析:创建了多种可视化图表,深入分析了特征重要性、模型性能和数据规律。
关键发现
特征重要性:票价(Fare)、年龄(Age)和性别(Sex)是影响乘客生存率最重要的三个特征。
生存规律:泰坦尼克号灾难中的生存数据清晰地展示了社会阶层和性别对生存率的显著影响,验证了历史记录中的”妇女和儿童优先”以及头等舱乘客优先的救援策略。
模型性能:集成学习方法(随机森林和梯度提升树)在这个问题上表现优于单一决策树和线性模型,这可能是因为它们能够更好地捕捉特征之间的非线性关系。
技术亮点
完整的机器学习管道:使用scikit-learn的Pipeline和ColumnTransformer构建了端到端的机器学习流程,确保了数据处理和模型训练的一致性。
稳健的评估方法:采用5折交叉验证评估模型性能,减少了过拟合风险,获得了更可靠的结果。
高效的特征工程:通过创建新特征和智能填充缺失值,显著提高了模型的预测性能。
丰富的可视化:使用多种可视化技术深入理解数据和模型,从不同角度揭示了问题本质。
未来改进方向
虽然我们的模型已经取得了不错的性能,但仍有许多可能的改进方向:
超参数优化:可以使用网格搜索(Grid Search)或随机搜索(Random Search)对模型超参数进行更细致的调优,可能会进一步提高模型性能。
特征工程深化:
尝试更多的特征组合和交互特征从姓名、票号等文本特征中提取更多有价值的信息使用聚类或其他技术创建新的特征表示
高级模型尝试:
使用深度学习模型,如神经网络,探索更深层次的特征学习尝试堆叠集成(Stacking)或投票集成(Voting)等更复杂的集成学习方法使用XGBoost、LightGBM或CatBoost等梯度提升框架
不平衡数据处理:考虑使用SMOTE等技术处理类别不平衡问题,可能会改善模型在少数类(存活乘客)上的性能。
更全面的评估指标:在准确率的基础上,考虑使用ROC曲线、AUC分数、精确率-召回率曲线等更全面的评估指标,特别是当不同类型错误的代价不同时。
项目意义
这个项目不仅是一个机器学习练习,也有实际的业务和学术意义:
方法论价值:展示了完整的机器学习项目流程,为类似的分类问题提供了可复用的方法论。
历史洞见:通过数据分析揭示了历史事件中的模式和规律,为理解历史提供了新的视角。
实用技能:项目中使用的技术和方法在金融风控、医疗诊断、客户流失预测等许多实际业务场景中都有广泛应用。
结语
泰坦尼克号生存预测是机器学习领域的经典问题,通过这个项目,我们不仅学习了各种机器学习算法和技术,也培养了从数据中提取规律的能力。最重要的是,我们展示了如何将理论知识应用到实际问题中,构建完整的端到端解决方案。
随着技术的不断发展,机器学习模型的性能会继续提高,但对数据的理解、特征工程的技巧和模型选择的判断仍然是机器学习工程师最核心的能力。希望本文能为读者提供有益的参考和启发,共同探索机器学习的无限可能。
