泰坦尼克号生存预测:机器学习实战指南(三十)
- 机器学习
- 2天前
- 8热度
- 0评论
如果你刚开始接触机器学习,可能会觉得那些复杂的算法和数学公式离现实生活很遥远。但今天,我们将通过一个经典案例——泰坦尼克号生存预测,带你亲身体验一次完整的机器学习项目流程。
泰坦尼克号数据集是机器学习领域最著名的入门项目之一,它基于 1912 年泰坦尼克号沉船事件中乘客的真实信息。我们的目标是:根据乘客的年龄、性别、船票等级等信息,构建一个模型来预测他们在灾难中是否能够幸存。
这个项目之所以经典,是因为它完美地涵盖了机器学习项目的核心步骤:
- 数据理解与探索
- 数据清洗与预处理
- 特征工程
- 模型选择与训练
- 模型评估与优化
通过这个实战案例,你将不再只是阅读理论,而是真正理解如何将机器学习应用于解决实际问题。
第一步:理解我们的数据
在动手写任何代码之前,我们必须先了解手头的数据。泰坦尼克号数据集通常包含以下字段(特征):
| 字段名 | 说明 | 数据类型 | 备注 |
|---|---|---|---|
| PassengerId | 乘客ID | 整数 | 唯一标识符,对预测无帮助 |
| Survived | 是否幸存 | 整数 (0/1) | 目标变量,0=遇难,1=幸存 |
| Pclass | 船票等级 | 整数 (1,2,3) | 1=头等舱,2=二等舱,3=三等舱 |
| Name | 乘客姓名 | 字符串 | 包含称谓(如 Mr., Miss.),可提取新特征 |
| Sex | 性别 | 字符串 | male或female |
| Age | 年龄 | 浮点数 | 有部分缺失值 |
| SibSp | 同行的兄弟姐妹/配偶数量 | 整数 | |
| Parch | 同行的父母/子女数量 | 整数 | |
| Ticket | 船票编号 | 字符串 | 结构复杂,信息量可能有限 |
| Fare | 船票价格 | 浮点数 | |
| Cabin | 船舱号 | 字符串 | 大量缺失值,但首字母可能代表船舱区域 |
| Embarked | 登船港口 | 字符串 | C=Cherbourg, Q=Queenstown, S=Southampton |
核心洞察:从历史知识我们知道,当时奉行"妇女和儿童优先"的原则,且头等舱乘客有优先使用救生艇的权利。因此,我们预期 Sex, Age, Pclass 等特征将对预测结果产生重大影响。
第二步:数据清洗与预处理
原始数据几乎从不完美。数据清洗就像为模型准备高质量的食材,这一步至关重要。
我们将使用 Python 的 pandas 和 numpy 库来完成这项工作。首先,我们需要读取并检查数据。
import pandas as pd
# 读取数据
train_data = pd.read_csv('train.csv')
test_data = pd.read_csv('test.csv')
# 查看数据基本信息
print(f"训练集形状: {train_data.shape}")
print(train_data.info())
print(train_data.head())运行上述代码后,你可能会发现两个主要问题:缺失值 和 非数值型数据。
处理缺失值
缺失值会影响模型的性能,因此我们需要对其进行处理。对于 Age 列,我们可以用中位数填充;对于 Embarked 列,可以用最常见的登船港口填充;对于 Fare 列,可以用中位数填充;而对于 Cabin 列,由于缺失值太多,我们直接删除该列。
# 处理 Age 列的缺失值
train_data['Age'].fillna(train_data['Age'].median(), inplace=True)
test_data['Age'].fillna(test_data['Age'].median(), inplace=True)
# 处理 Embarked 列的缺失值
most_common_port = train_data['Embarked'].mode()[0]
train_data['Embarked'].fillna(most_common_port, inplace=True)
test_data['Embarked'].fillna(most_common_port, inplace=True)
# 处理 Fare 列的缺失值
test_data['Fare'].fillna(test_data['Fare'].median(), inplace=True)
# 删除 Cabin 列
train_data.drop(columns=['Cabin'], inplace=True)
test_data.drop(columns=['Cabin'], inplace=True)转换非数值型数据
机器学习模型通常只能处理数值。我们需要将 Sex 和 Embarked 这样的文本列转换为数字。
# 转换 Sex 列
train_data['Sex'] = train_data['Sex'].map({'female': 0, 'male': 1})
test_data['Sex'] = test_data['Sex'].map({'female': 0, 'male': 1})
# 对 Embarked 列进行 one-hot 编码
train_data = pd.get_dummies(train_data, columns=['Embarked'])
test_data = pd.get_dummies(test_data, columns=['Embarked'])第三步:特征工程
特征工程是机器学习中的“魔法”,它通过创造或转换特征来帮助模型更好地学习。我们从 Name 列中提取“称谓”就是一个经典例子。
# 提取称谓
train_data['Title'] = train_data['Name'].str.extract(' ([A-Za-z]+)\.', expand=False)
test_data['Title'] = test_data['Name'].str.extract(' ([A-Za-z]+)\.', expand=False)
# 打印称谓与性别的交叉表
print(pd.crosstab(train_data['Title'], train_data['Sex']))
# 映射称谓
title_mapping = {
'Mr': 'Mr', 'Miss': 'Miss', 'Mrs': 'Mrs',
'Master': 'Master', 'Dr': 'Rare', 'Rev': 'Rare',
'Col': 'Rare', 'Major': 'Rare', 'Mlle': 'Miss',
'Countess': 'Rare', 'Ms': 'Miss', 'Lady': 'Rare',
'Jonkheer': 'Rare', 'Don': 'Rare', 'Dona': 'Rare',
'Mme': 'Mrs', 'Capt': 'Rare', 'Sir': 'Rare'
}
train_data['Title'] = train_data['Title'].map(title_mapping)
test_data['Title'] = test_data['Title'].map(title_mapping)
# 对 Title 列进行 one-hot 编码
train_data = pd.get_dummies(train_data, columns=['Title'])
test_data = pd.get_dummies(test_data, columns=['Title'])
# 创建 FamilySize 和 IsAlone 特征
train_data['FamilySize'] = train_data['SibSp'] + train_data['Parch'] + 1
test_data['FamilySize'] = test_data['SibSp'] + test_data['Parch'] + 1
train_data['IsAlone'] = (train_data['FamilySize'] == 1).astype(int)
test_data['IsAlone'] = (test_data['FamilySize'] == 1).astype(int)
# 删除不需要的列
columns_to_drop = ['PassengerId', 'Name', 'Ticket', 'SibSp', 'Parch']
train_data.drop(columns_to_drop, axis=1, inplace=True)
test_passenger_ids = test_data['PassengerId']
test_data.drop(columns_to_drop, axis=1, inplace=True)
# 打印特征工程后的训练集列名
print("特征工程后的训练集列名:", train_data.columns.tolist())第四步:选择与训练模型
现在,我们有了干净且富含信息的数值数据。接下来,我们将其分为特征 (X) 和目标变量 (y),然后选择一个模型进行训练。我们将从简单且高效的 随机森林 (Random Forest) 模型开始。
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# 分割特征和目标变量
X = train_data.drop('Survived', axis=1)
y = train_data['Survived']
# 划分训练集和验证集
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练随机森林模型
model = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
model.fit(X_train, y_train)
# 预测并计算准确率
y_pred = model.predict(X_val)
accuracy = accuracy_score(y_val, y_pred)
print(f"模型在验证集上的准确率为:{accuracy:.4f} (即 {accuracy*100:.2f}%)")第五步:模型评估、优化与提交
评估与优化
一次训练的结果可能不是最优的。我们可以通过以下方式改进:
- 调整模型参数:例如,尝试不同的 n_estimators 或 max_depth。
- 尝试其他模型:比如逻辑回归、支持向量机、梯度提升树等。
- 进一步的特征工程:比如对 Age 或 Fare 进行分箱处理。
# 调整 max_depth 参数
for depth in [3, 5, 10, None]:
model_temp = RandomForestClassifier(n_estimators=100, max_depth=depth, random_state=42)
model_temp.fit(X_train, y_train)
y_pred_temp = model_temp.predict(X_val)
acc = accuracy_score(y_val, y_pred_temp)
print(f"max_depth={depth} 时,验证集准确率:{acc:.4f}")特征重要性分析
随机森林可以告诉我们哪些特征对预测贡献最大。
# 获取特征重要性
feature_importances = pd.DataFrame({
'Feature': X_train.columns,
'Importance': model.feature_importances_
}).sort_values(by='Importance', ascending=False)
print(feature_importances)总结
通过本文,我们详细介绍了如何从数据理解与探索、数据清洗与预处理、特征工程、模型选择与训练,到最后的模型评估与优化,完成一个完整的机器学习项目。希望这个实战案例能帮助你更好地理解和应用机器学习技术。如果你有任何疑问或建议,欢迎在评论区留言交流!