泰坦尼克号沉船事件是机器学习领域最经典的入门项目之一。Kaggle 上的 Titanic: Machine Learning from Disaster 竞赛,被无数人称为“机器学习的 Hello World”。
一、数据导入与清洗:让数据从 “杂乱” 变 “干净”
机器学习模型就像 “挑食的孩子”,只吃 “数值型、无缺失” 的数据。但原始数据往往充满 “漏洞”,所以第一步必须先做数据清洗。
1.1 第一步:导入工具库与加载数据
# 导入必备库
import pandas as pd
import numpy as np
# 加载训练集(带生存标签)和测试集(需预测生存)
df_train = pd.read_csv('train.csv') # 891条数据,含Survived列(1=幸存,0=遇难)
df_test = pd.read_csv('test.csv') # 418条数据,无Survived列
1.2 第二步:检查数据 “漏洞”—— 找缺失值
数据缺失是最常见的问题,我们先写一个函数,直观展示哪些列有缺失:
def show_missing(df, name="DataFrame"):
# 统计每列缺失值数量
missing = df.isnull().sum()
# 只保留有缺失的列
missing = missing[missing > 0]
if len(missing) == 0:
print(f"✅ {name} 中无缺失值")
else:
print(f"⚠️ {name} 中存在缺失值:")
print(missing)
# 检查训练集和测试集
show_missing(df_train, "训练集")
show_missing(df_test, "测试集")
运行结果:
⚠️ 训练集中存在缺失值:
Age 177 # 177个乘客年龄缺失
Cabin 687 # 687个乘客船舱号缺失(占比77%)
Embarked 2 # 2个乘客登船港口缺失
⚠️ 测试集中存在缺失值:
Age 86 # 86个年龄缺失
Fare 1 # 1个票价缺失
Cabin 327 # 327个船舱号缺失
看到这些缺失值,不能直接删数据(会浪费信息),需要针对性处理。
1.3 第三步:缺失值处理 —— 用 “合理逻辑” 补全数据
缺失值处理的核心原则:基于业务逻辑选择填充方式,避免 “随便填数”。
(1)年龄(Age):按 “头衔” 智能填充
直接用 “全体年龄中位数” 填充不合理(比如 “儿童” 和 “老人” 年龄差异大)。但姓名中藏着 “头衔”(如 Mr = 先生、Mrs = 夫人、Miss = 小姐、Master = 少爷),不同头衔的年龄分布很规律 —— 这是关键突破口!
# 1. 从姓名中提取头衔
def extract_title(name):
if pd.isna(name): # 极端情况:姓名为空(实际数据中没有)
return 'Unknown'
# 姓名格式如“Braund, Mr. Owen Harris”,按逗号和句号分割取“Mr”
title = name.split(',')[1].split('.')[0].strip()
# 只保留常见头衔,少见的(如 Sir、Lady)归为“Other”
if title not in ['Mr', 'Mrs', 'Miss', 'Master']:
return 'Other'
return title
# 给训练集和测试集添加“头衔”列
df_train['Title'] = df_train['Name'].apply(extract_title)
df_test['Title'] = df_test['Name'].apply(extract_title)
# 2. 按头衔计算训练集的年龄中位数(用训练集数据,避免“数据泄露”)
title_age_median = df_train.groupby('Title')['Age'].median()
print("按头衔分组的年龄中位数:")
print(title_age_median)
# 3. 按头衔填充缺失年龄
for title in title_age_median.index:
# 填充训练集
df_train.loc[(df_train['Age'].isnull()) & (df_train['Title'] == title), 'Age'] = title_age_median[title]
# 填充测试集(用训练集的中位数,保证数据一致性)
df_test.loc[(df_test['Age'].isnull()) & (df_test['Title'] == title), 'Age'] = title_age_median[title]
运行结果:
按头衔分组的年龄中位数:
Title
Master 3.5 # 少爷(儿童):3.5岁
Miss 21.0 # 小姐(青年女性):21岁
Mr 32.0 # 先生(成年男性):32岁
Mrs 36.0 # 夫人(成年女性):36岁
Other 42.0 # 其他头衔(如医生、军官):42岁
用对应头衔的年龄中位数填充,比 “全体中位数” 精准得多!
(2)登船港口(Embarked):用 “众数” 填充
Embarked是分类变量(S = 南安普顿、C = 瑟堡、Q = 昆士敦),缺失值用 “出现次数最多的值(众数)” 填充 —— 因为 “多数人的选择更可能接近真实情况”。
# 计算训练集Embarked的众数(mode()[0]取第一个众数,避免返回Series)
embarked_mode = df_train['Embarked'].mode()[0]
print(f"训练集登船港口众数:{embarked_mode}")
# 填充缺失值
df_train['Embarked'] = df_train['Embarked'].fillna(embarked_mode)
df_test['Embarked'] = df_test['Embarked'].fillna(embarked_mode)
运行结果:训练集登船港口众数:S(大部分乘客从 S 港口登船)。
(3)票价(Fare):用 “中位数” 填充
Fare是数值变量,但可能有极端值(比如头等舱票价极高),用 “中位数” 填充比 “平均值” 更稳健(不受极端值影响)。这里用sklearn

最低0.47元/天 解锁文章
1931

被折叠的 条评论
为什么被折叠?



