项目:泰坦尼克沉船事件乘客幸存预测¶

事件背景¶

泰坦尼克号(RMS Titanic)是一艘奥林匹克级邮轮,于1912年4月首航时撞上冰山后沉没。泰坦尼克号是同级的3艘超级邮轮中的第2艘,与姐妹船奥林匹克号和不列颠号为白星航运公司的乘客们提供大西洋旅行。

泰坦尼克号由位于北爱尔兰贝尔法斯特的哈兰·沃尔夫船厂兴建,是当时最大的客运轮船,由于其规模相当一艘现代航空母舰,因而号称“上帝也沉没不了的巨型邮轮”。在泰坦尼克号的首航中,从英国南安普敦出发,途经法国瑟堡-奥克特维尔以及爱尔兰昆士敦,计划横渡大西洋前往美国纽约市。但因为人为错误,于1912年4月14日船上时间夜里11点40分撞上冰山;2小时40分钟后,即4月15日凌晨02点20分,船裂成两半后沉入大西洋,死亡人数超越1500人,堪称20世纪最大的海难事件,同时也是最广为人知的海难之一。

项目目标¶

基于泰坦尼克号乘客的性别和船舱等级等属性,对幸存情况进行逻辑回归分析,挖掘影响乘客幸存的重要特征,并利用回归模型预测未知幸存情况的乘客是否从沉船事件中幸存。

数据描述¶

数据集包括两个数据表:train.csv和test.csv

train.csv:记录了891位泰坦尼克号乘客在沉船事件后的幸存情况,用于进行模型训练,具体字段信息如下

  • PassengerId:乘客ID
  • survival:是否幸存
    • 0 否
    • 1 是
  • pclass:船舱等级
    • 1 一等舱
    • 2 二等舱
    • 3 三等舱
  • name:姓名
  • sex:性别
  • Age:年龄
  • sibsp:同乘伴侣/同胞数量
  • parch:同乘父母/孩子数量
  • ticket:船票号
  • fare:票价金额
  • cabin:船舱号
  • embarked:登船港口
    • C 瑟堡
    • Q 皇后镇
    • S 南安普敦

test.csv:记录泰坦尼克号上其他418名乘客的相关信息,用于预测乘客是否幸存(字段含义与train.csv相同,但不包含survival)

补充项目中扩展的新特征:

  • HasCabin:是否有登记船舱信息
    • 0 无登记船舱信息
    • 1 有登记船舱信息
  • FamilyNum:乘客在船上的家庭成员个数

结论前置¶

泰坦尼克号沉船事件中,乘客生还几率受年龄、家庭规模、船舱等级、性别以及是否有船舱记录影响显著:

  • 年龄越大,生还几率越低:年龄每增加1岁,生还几率降低 3.69%
  • 家庭规模越大,生还几率越低:每多1名同乘家庭成员,生还几率降低 20.55%
  • 船舱越高级,生还几率越高:三等舱乘客的生还几率比一等舱乘客低 70.52%
  • 优先救援女性乘客:男性乘客的生还几率比女性乘客低 93.70%
  • 优先救援有登记船舱信息的乘客:有登记船舱信息的乘客生还几率比无登记乘客高 257.12%

读取数据¶

In [1]:
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns

import statsmodels.api as sm
In [2]:
origin_train = pd.read_csv("train.csv")  # 读入训练集文件

数据评估与清洗¶

In [3]:
clean_train = origin_train.copy()  # 复制一份训练集,用于进行数据清洗

数据整齐度评估¶

In [4]:
clean_train.head()  # 查看文件前5行
Out[4]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 C123 S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 NaN S

从总体来看,这份训练集结构清晰,数据整齐,不存在结构性问题。

数据干净度评估¶

In [5]:
clean_train.info()  # 获取数据集概览
<class 'pandas.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    str    
 4   Sex          891 non-null    str    
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    str    
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    str    
 11  Embarked     889 non-null    str    
dtypes: float64(2), int64(5), str(5)
memory usage: 83.7 KB

数据干净度分析¶

  • 训练数据集共891个数据(891个人)
  • 每个人都有12个特征
  • 存在缺失值:
    • Age(年龄)特征缺失了117个数据
    • Cabin(船舱号)特征缺失了687个数据
    • Embarked(登船港口)特征缺失了2个数据
  • 数据类型异常:
    • PassengerId(乘客ID)是乘客的唯一标识符,应该是字符串类型数据,而不是整型
    • Survived(是否幸存)、Pclass(船舱等级)、Sex(性别)、Embarked(登船港口)都是分类特征,但这些特征的数据类型各异

缺失值处理¶

Age缺失值处理¶
  • Age(年龄)特征缺失了117个数据,占总体数据比例的13%。
  • 因缺失比例适中且其他特征信息完整,采用整体均值填充,在保证样本量的同时避免引入额外偏差。
In [6]:
clean_train[clean_train['Age'].isnull()] # 查看Age列存在缺失值的表格数据
Out[6]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
5 6 0 3 Moran, Mr. James male NaN 0 0 330877 8.4583 NaN Q
17 18 1 2 Williams, Mr. Charles Eugene male NaN 0 0 244373 13.0000 NaN S
19 20 1 3 Masselmani, Mrs. Fatima female NaN 0 0 2649 7.2250 NaN C
26 27 0 3 Emir, Mr. Farred Chehab male NaN 0 0 2631 7.2250 NaN C
28 29 1 3 O'Dwyer, Miss. Ellen "Nellie" female NaN 0 0 330959 7.8792 NaN Q
... ... ... ... ... ... ... ... ... ... ... ... ...
859 860 0 3 Razi, Mr. Raihed male NaN 0 0 2629 7.2292 NaN C
863 864 0 3 Sage, Miss. Dorothy Edith "Dolly" female NaN 8 2 CA. 2343 69.5500 NaN S
868 869 0 3 van Melkebeke, Mr. Philemon male NaN 0 0 345777 9.5000 NaN S
878 879 0 3 Laleff, Mr. Kristo male NaN 0 0 349217 7.8958 NaN S
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female NaN 1 2 W./C. 6607 23.4500 NaN S

177 rows × 12 columns

In [7]:
clean_train['Age'] = clean_train['Age'].fillna(clean_train['Age'].mean())  # 用 Age 列数据的平均值填充 Age 列的 NaN 值
clean_train['Age'].isnull().sum()  # 验证 Age 列的 NaN 值是否已被填充
Out[7]:
np.int64(0)
Cabin缺失值处理¶
  • Cabin(船舱号)特征缺失687条(占77%),缺失率极高,无法有效填充。
  • 考虑到Cabin可能反映乘客距救生艇的远近,与生存率存在潜在关联,因此不直接删除该特征。
  • 为此,本项目根据乘客船舱信息是否缺失,将该特征重构为“HasCabin”,定义“有登记船舱信息为1,无登记船舱信息为0”,将“缺失”本身转化为有效信号。
In [8]:
clean_train[clean_train['Cabin'].isnull()]  # 查看Cabin列存在缺失值的表格数据
Out[8]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.000000 1 0 A/5 21171 7.2500 NaN S
2 3 1 3 Heikkinen, Miss. Laina female 26.000000 0 0 STON/O2. 3101282 7.9250 NaN S
4 5 0 3 Allen, Mr. William Henry male 35.000000 0 0 373450 8.0500 NaN S
5 6 0 3 Moran, Mr. James male 29.699118 0 0 330877 8.4583 NaN Q
7 8 0 3 Palsson, Master. Gosta Leonard male 2.000000 3 1 349909 21.0750 NaN S
... ... ... ... ... ... ... ... ... ... ... ... ...
884 885 0 3 Sutehall, Mr. Henry Jr male 25.000000 0 0 SOTON/OQ 392076 7.0500 NaN S
885 886 0 3 Rice, Mrs. William (Margaret Norton) female 39.000000 0 5 382652 29.1250 NaN Q
886 887 0 2 Montvila, Rev. Juozas male 27.000000 0 0 211536 13.0000 NaN S
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female 29.699118 1 2 W./C. 6607 23.4500 NaN S
890 891 0 3 Dooley, Mr. Patrick male 32.000000 0 0 370376 7.7500 NaN Q

687 rows × 12 columns

In [9]:
# 构造一个新的列,有登记船舱信息记为1,无登记船舱信息记为0
clean_train['HasCabin'] = clean_train['Cabin'].notnull().astype("int")  # 构造出 HasCabin 列
clean_train[['Cabin','HasCabin']]
Out[9]:
Cabin HasCabin
0 NaN 0
1 C85 1
2 NaN 0
3 C123 1
4 NaN 0
... ... ...
886 NaN 0
887 B42 1
888 NaN 0
889 C148 1
890 NaN 0

891 rows × 2 columns

In [10]:
clean_train = clean_train.drop("Cabin",axis=1)  # 将无用的 Cabin 列从原表中删除
clean_train
Out[10]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Embarked HasCabin
0 1 0 3 Braund, Mr. Owen Harris male 22.000000 1 0 A/5 21171 7.2500 S 0
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.000000 1 0 PC 17599 71.2833 C 1
2 3 1 3 Heikkinen, Miss. Laina female 26.000000 0 0 STON/O2. 3101282 7.9250 S 0
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.000000 1 0 113803 53.1000 S 1
4 5 0 3 Allen, Mr. William Henry male 35.000000 0 0 373450 8.0500 S 0
... ... ... ... ... ... ... ... ... ... ... ... ...
886 887 0 2 Montvila, Rev. Juozas male 27.000000 0 0 211536 13.0000 S 0
887 888 1 1 Graham, Miss. Margaret Edith female 19.000000 0 0 112053 30.0000 S 1
888 889 0 3 Johnston, Miss. Catherine Helen "Carrie" female 29.699118 1 2 W./C. 6607 23.4500 S 0
889 890 1 1 Behr, Mr. Karl Howell male 26.000000 0 0 111369 30.0000 C 1
890 891 0 3 Dooley, Mr. Patrick male 32.000000 0 0 370376 7.7500 Q 0

891 rows × 12 columns

Embarked 缺失值处理¶
  • Embarked(登船港口)特征缺失了2个数据,而且Embarked是一个分类变量,所以采用众数填充方式对缺失值进行填充。
In [11]:
clean_train[clean_train['Embarked'].isnull()]  # 查看Embarked列存在缺失值的表格数据
Out[11]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Embarked HasCabin
61 62 1 1 Icard, Miss. Amelie female 38.0 0 0 113572 80.0 NaN 1
829 830 1 1 Stone, Mrs. George Nelson (Martha Evelyn) female 62.0 0 0 113572 80.0 NaN 1
In [12]:
embarked_mode = clean_train['Embarked'].mode()  # 计算Embarked的众数
clean_train['Embarked'] = clean_train['Embarked'].fillna(embarked_mode[0])  # 把众数填充进缺失位置
clean_train['Embarked'].isnull().sum()  # 重新统计缺失值个数,确保正确填充缺失值
Out[12]:
np.int64(0)

处理异常类型¶

将 PassengerId 转为字符串类型¶
  • PassengerId 表示每个乘客的唯一 ID,不应被用于数值计算,因此需要将其转位字符串类型
In [13]:
clean_train['PassengerId'] = clean_train['PassengerId'].astype("str")  # 把 PassengerId 列的数据类型设置为 str
clean_train.info()
<class 'pandas.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    str    
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    str    
 4   Sex          891 non-null    str    
 5   Age          891 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    str    
 9   Fare         891 non-null    float64
 10  Embarked     891 non-null    str    
 11  HasCabin     891 non-null    int64  
dtypes: float64(2), int64(5), str(5)
memory usage: 83.7 KB
Survived、Pclass、Sex、Embarked、HasCabin转为分类类型¶
  • Survived、Pclass、Sex、Embarked、HasCabin都是分类特征,但这些特征的数据类型各异,所以需要更改为 category 类型
In [14]:
clean_train['Survived'] = clean_train['Survived'].astype('category')  # 更改 Survived 列
clean_train['Survived']
Out[14]:
0      0
1      1
2      1
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: Survived, Length: 891, dtype: category
Categories (2, int64): [0, 1]
In [15]:
clean_train['Pclass'] = clean_train['Pclass'].astype('category')  # 更改 Pclass 列
clean_train['Pclass']
Out[15]:
0      3
1      1
2      3
3      1
4      3
      ..
886    2
887    1
888    3
889    1
890    3
Name: Pclass, Length: 891, dtype: category
Categories (3, int64): [1, 2, 3]
In [16]:
clean_train['Sex'] = clean_train['Sex'].astype('category')  # 更改 Sex 列
clean_train['Sex']
Out[16]:
0        male
1      female
2      female
3      female
4        male
        ...  
886      male
887    female
888    female
889      male
890      male
Name: Sex, Length: 891, dtype: category
Categories (2, str): ['female', 'male']
In [17]:
clean_train['Embarked'] = clean_train['Embarked'].astype('category')  # 更改 Embarked 列
clean_train['Embarked']
Out[17]:
0      S
1      C
2      S
3      S
4      S
      ..
886    S
887    S
888    S
889    C
890    Q
Name: Embarked, Length: 891, dtype: category
Categories (3, str): ['C', 'Q', 'S']
In [18]:
clean_train['HasCabin'] = clean_train['HasCabin'].astype('category')  # 更改 HasCabin 列
clean_train['HasCabin']
Out[18]:
0      0
1      1
2      0
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: HasCabin, Length: 891, dtype: category
Categories (2, int64): [0, 1]

数据重复评估¶

  • PassengerId 表示每个乘客的唯一 ID,不能存在重复,需要检查该列是否有异常
In [19]:
clean_train["PassengerId"].duplicated().sum()
Out[19]:
np.int64(0)

小结:输出为 0,说明不存在重复值

数据一致性评估¶

  • 不一致数据可能存在于所有分类特征中,需要查看是否存在不同值实际指代同一目标的情况
  • 分类特征:Survived、Pclass、Sex、Embarked、HasCabin
In [20]:
clean_train['Survived'].value_counts()  # 幸存结果分类
Out[20]:
Survived
0    549
1    342
Name: count, dtype: int64
In [21]:
clean_train['Pclass'].value_counts()  # 船舱等级分类
Out[21]:
Pclass
3    491
1    216
2    184
Name: count, dtype: int64
In [22]:
clean_train['Sex'].value_counts()  # 性别分类
Out[22]:
Sex
male      577
female    314
Name: count, dtype: int64
In [23]:
clean_train['Embarked'].value_counts()  # 登船港口分类
Out[23]:
Embarked
S    646
C    168
Q     77
Name: count, dtype: int64
In [24]:
clean_train['HasCabin'].value_counts()  #是否有登记船舱分类
Out[24]:
HasCabin
0    687
1    204
Name: count, dtype: int64

小结:所有分类特征数据都一致

无效或错误数据评估¶

  • 无效或错误数据可能导致模型预测准确性降低,需要先行处理
In [25]:
clean_train.describe()
Out[25]:
Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 891.000000
mean 29.699118 0.523008 0.381594 32.204208
std 13.002015 1.102743 0.806057 49.693429
min 0.420000 0.000000 0.000000 0.000000
25% 22.000000 0.000000 0.000000 7.910400
50% 29.699118 0.000000 0.000000 14.454200
75% 35.000000 1.000000 0.000000 31.000000
max 80.000000 8.000000 6.000000 512.329200

小结:不存在异常值

  • 乘客年龄平均为30岁左右,最大值为80岁,最小值为0.42岁。
  • 同乘伴侣/同胞数量最大值为8个,最小为0个。
  • 同乘父母/孩子数量最大值为6个,最小值为0个。
  • 船票价格平均为32元,最大值为512元,最小值为0元【0元有可能是赠票,所以不算异常值】。

特征扩展¶

  • SibSp 表示同乘的伴侣/同胞数,Parch 表示同乘的父母/孩子数,这个两个特征表示的都是这个乘客的家人。
  • 假设这个乘客家人很多,那他因为拯救家人而遇难的可能性就会大增,因此认为家人的多少是影响乘客幸存的重要因素。
  • 由此,可以构造成一个新特征,表示“乘客在船上的家庭成员个数”,指定特征名为“FamilyNum”
In [26]:
clean_train["FamilyNum"] = clean_train["SibSp"] + clean_train["Parch"]  # 家庭成员人数 = 同伴或同胞数 + 父母或孩子数
clean_train.head(10)
Out[26]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Embarked HasCabin FamilyNum
0 1 0 3 Braund, Mr. Owen Harris male 22.000000 1 0 A/5 21171 7.2500 S 0 1
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.000000 1 0 PC 17599 71.2833 C 1 1
2 3 1 3 Heikkinen, Miss. Laina female 26.000000 0 0 STON/O2. 3101282 7.9250 S 0 0
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.000000 1 0 113803 53.1000 S 1 1
4 5 0 3 Allen, Mr. William Henry male 35.000000 0 0 373450 8.0500 S 0 0
5 6 0 3 Moran, Mr. James male 29.699118 0 0 330877 8.4583 Q 0 0
6 7 0 1 McCarthy, Mr. Timothy J male 54.000000 0 0 17463 51.8625 S 1 0
7 8 0 3 Palsson, Master. Gosta Leonard male 2.000000 3 1 349909 21.0750 S 0 4
8 9 1 3 Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg) female 27.000000 0 2 347742 11.1333 S 0 2
9 10 1 2 Nasser, Mrs. Nicholas (Adele Achem) female 14.000000 1 0 237736 30.0708 C 0 1

数据探索¶

探索幸存比例¶

In [27]:
sns.set_palette("pastel")  # 设置图表的配色方案
plt.rcParams['figure.figsize'] = (7, 3.5)  # 设置全局图表宽、高
plt.rcParams["figure.autolayout"] = True  # 自动调整子图间距

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 黑体
plt.rcParams['axes.unicode_minus'] = False    # 解决负号 '-' 显示为方块
In [28]:
survived_count = clean_train['Survived'].value_counts()  # 统计Survived中每个类别的个数
survived_count
Out[28]:
Survived
0    549
1    342
Name: count, dtype: int64
In [29]:
plt.pie(survived_count, labels=['遇难','幸存'], autopct="%.2f%%")
plt.show()
No description has been provided for this image

小结:泰坦尼克号遇难乘客远多于幸存乘客,比例约为3:2

  • 幸存342人,占总人数的38.38%
  • 遇难549人,占总人数的61.62%

探索船舱等级与是否幸存之间的相关关系¶

In [30]:
pclass_count_all = clean_train['Pclass'].value_counts()  # 统计不同等级船舱的人数
pclass_count_all
Out[30]:
Pclass
3    491
1    216
2    184
Name: count, dtype: int64
In [31]:
# 统计不同等级船舱的幸存人数
survived_df = clean_train[clean_train['Survived'] == 1]  # 筛选出所有幸存乘客信息
pclass_count_survived = survived_df['Pclass'].value_counts()  # 统计不同等级船舱的幸存人数
pclass_count_survived
Out[31]:
Pclass
1    136
3    119
2     87
Name: count, dtype: int64
In [32]:
fig, axes = plt.subplots(1, 2)  # 绘制1行2列的子图图框
axes[0].pie(pclass_count_all, labels=['3', '1', '2'], autopct="%.2f%%")  # 绘制饼图,展示不同等级船舱的人数比例
sns.countplot(clean_train, x="Pclass", hue="Survived", ax=axes[1])  # 绘制计数图,展现不同船舱等级的人员的幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:船舱越高级,乘客幸存率越高,船舱等级与是否幸存之间存在正相关关系

  • 一等舱216人,占总人数的24.24%,幸存136人,幸存率63.96%
  • 二等舱184人,占总人数的20.65%,幸存87人,幸存率47.28%
  • 三等舱491人,占总人数的55.11%,幸存119人,幸存率24.23%

探索性别与是否幸存之间的相关关系¶

In [33]:
sex_count_all = clean_train['Sex'].value_counts()  # 统计不同性别的人数
sex_count_all
Out[33]:
Sex
male      577
female    314
Name: count, dtype: int64
In [34]:
# 统计不同性别的幸存人数
survived_df = clean_train[clean_train['Survived'] == 1]  # 筛选出所有幸存乘客信息
sex_count_survived = survived_df['Sex'].value_counts()  # 统计不同性别的幸存人数
sex_count_survived
Out[34]:
Sex
female    233
male      109
Name: count, dtype: int64
In [35]:
fig, axes = plt.subplots(1, 2)  # 绘制1行2列的子图图框
axes[0].pie(sex_count_all, labels=['male', 'female'], autopct="%.2f%%")  # 绘制饼图,展示不同性别人数占比
sns.countplot(clean_train, x='Sex', hue='Survived', ax=axes[1])  # 绘制计数图,展示不同性别人员幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:女性乘客的幸存率远高于男性乘客,由此推测性别与是否幸存之间存在相关关系

  • 女性乘客314人,占总人数的35.2%,幸存233人,幸存率74.20%
  • 男性乘客577人,占总人数的64.8%,幸存109人,幸存率18.89%

探索乘客的年龄分布情况¶

In [36]:
fig, axes = plt.subplots(1, 2, gridspec_kw={"width_ratios": [1, 5]})  # 绘制1行2列的子图图框
sns.boxplot(clean_train['Age'], ax=axes[0])  # 绘制箱形图,用于展示乘客年龄的集中趋势
sns.histplot(clean_train, x='Age')  # 绘制直方图,用于展示乘客年龄的总体分布情况
plt.show()
No description has been provided for this image

小结:大多数乘客年龄位于22岁到40岁之间,且有不少婴幼儿及老年乘客

  • 乘客年龄主要集中于22岁到40岁之间,呈双峰右偏分布,一峰代表婴幼儿,另一峰代表青壮年乘客,长尾代表老年乘客

探索年龄与是否幸存之间的相关关系¶

In [37]:
sns.histplot(clean_train, x='Age', hue='Survived', alpha=0.4)  # 绘制直方图,展示不同年龄人员幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:幸存比例在婴幼儿峰中较高,青壮年峰及老年长尾所对应的年龄段遇难人数均占多数,因此,年龄与是否幸存之间存在相关关系

探索乘客的年龄分布情况¶

In [38]:
fig, axes = plt.subplots(1, 2, figsize=(10, 5), gridspec_kw={"width_ratios": [1, 4]})  # 绘制1行2列的子图图框
sns.boxplot(clean_train['Fare'], ax=axes[0])  # 绘制箱形图,用于展示票价金额的集中趋势
sns.histplot(clean_train, x="Fare")  # 绘制直方图,用于展示乘客船票金额的总体分布情况
plt.show()
No description has been provided for this image

小结:船票金额呈右偏态分布,多数票价集中在0–40美元的低价区间,少量高价票构成右侧长尾,从而拉高整体平均值

探索票价金额与是否幸存之间的相关关系¶

In [39]:
sns.histplot(clean_train, x="Fare", hue="Survived")  # 绘制直方图,用于展示不同船票金额对应人员的幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:购买低价票(0-40美元)的乘客遇难人数均占多数,购买中高价票(40美元以上)的乘客幸存人数均占多数,因此,票价金额与是否幸存之间存在相关关系

探索登船港口与是否幸存之间的相关关系¶

In [40]:
embarked_count_all = clean_train['Embarked'].value_counts()  # 统计不同登船港口乘客的人数
embarked_count_all
Out[40]:
Embarked
S    646
C    168
Q     77
Name: count, dtype: int64
In [41]:
# 统计不同登船港口乘客的幸存人数
survived_df = clean_train[clean_train['Survived'] == 1]  # 筛选出所有幸存乘客信息
embarked_count_survived = survived_df['Embarked'].value_counts()  # 统计不同登船港口乘客的幸存人数
embarked_count_survived
Out[41]:
Embarked
S    219
C     93
Q     30
Name: count, dtype: int64
In [42]:
fig, axes = plt.subplots(1, 2)  # 绘制1行2列的子图图框
axes[0].pie(embarked_count_all, labels=['S', 'C', 'Q'], autopct='%.2f%%')  # 绘制饼图,用于表示不同港口登船的乘客的比例
sns.countplot(clean_train, x='Embarked', hue='Survived')  # 绘制计数图,用于展示不同登船港口对应乘客人数的幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:从瑟堡登船的乘客,幸存数量大于遇难数量,而皇后镇和南安普敦则相反,因此,登船港口与是否幸存之间存在相关关系

  • 从 S(南安普敦)港口登船的乘客有646人,占总人数的72.50%,幸存219人,幸存率33.90%
  • 从 C(瑟堡)港口登船的乘客有168人,占总人数的18.86%,幸存93人,幸存率55.35%
  • 从 Q(皇后镇)港口登船的乘客有77人,占总人数的8.64%,幸存30人,幸存率38.96%

探索是否有登记船舱信息与是否幸存之间的相关关系¶

In [43]:
has_cabin_count_all = clean_train['HasCabin'].value_counts()  # 统计有登记船舱信息和无登记船舱信息的人员的个数
has_cabin_count_all
Out[43]:
HasCabin
0    687
1    204
Name: count, dtype: int64
In [44]:
# 统计有登记船舱信息和无登记船舱信息的幸存人员的个数
survived_df = clean_train[clean_train['Survived'] == 1]  # 筛选出所有幸存乘客信息
has_cabin_count_survived = survived_df['HasCabin'].value_counts()  # 统计有登记船舱信息和无登记船舱信息的幸存人员的个数
has_cabin_count_survived
Out[44]:
HasCabin
0    206
1    136
Name: count, dtype: int64
In [45]:
fig, axes = plt.subplots(1, 2)  # 绘制1行2列的子图图框
axes[0].pie(has_cabin_count_all, labels=['0', '1'], autopct='%.2f%%')  # 绘制饼图,用于展示有无登记船舱信息人员的比例【0 表示‘无登记’,1 表示‘有登记’】
sns.countplot(clean_train, x='HasCabin', hue='Survived')  # 绘制计数图,用于展示有无登记船舱信息人员的幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:有登记船舱信息的乘客幸存人数多于遇难人数,无登记船舱信息的乘客遇难人数多余幸存人数,因此,是否有登记船舱信息与是否幸存之间存在相关关系

  • 无登记船舱信息的乘客有687人,占总人数的77.10%,幸存206人,幸存率29.99%
  • 有登记船舱信息的乘客有204人,占总人数的22.90%,幸存136人,幸存率66.67%

探索家庭成员数量与是否幸存之间的相关关系¶

In [46]:
family_num_count_all = clean_train['FamilyNum'].value_counts()  # 统计不同家庭成员数量乘客的人数
family_num_count_all
Out[46]:
FamilyNum
0     537
1     161
2     102
3      29
5      22
4      15
6      12
10      7
7       6
Name: count, dtype: int64
In [47]:
# 统计不同家庭成员数量乘客的幸存人数
survived_df = clean_train[clean_train['Survived'] == 1]  # 筛选出所有幸存乘客信息
family_num_count_survived = survived_df['FamilyNum'].value_counts()  # 统计不同家庭成员数量乘客的幸存人数
family_num_count_survived
Out[47]:
FamilyNum
0    163
1     89
2     59
3     21
6      4
5      3
4      3
Name: count, dtype: int64
In [48]:
fig, axes = plt.subplots(1, 2)  # 绘制1行2列的子图图框
axes[0].pie(family_num_count_all, labels=['0', '1', '2', '3', '5', '4', '6', '10', '7'])  # 绘制饼图,用于展示不同家庭成员数量的乘客的比例
sns.countplot(clean_train, x='FamilyNum', hue='Survived')  # 绘制计数图,用于展示不同家庭成员数量乘客的幸存人数对比【0 表示‘遇难’,1 表示‘幸存’】
plt.show()
No description has been provided for this image

小结:有1-3位其他家庭成员的乘客幸存人数多余遇难人数,无其他家庭成员的乘客与有4位以上家庭成员的乘客均遇难人数多于幸存人数,因此,家庭成员数量与是否幸存之间存在相关关系

  • 无其他家庭成员的乘客有537人,占总人数的60.27%,幸存163人,幸存率30.35%
  • 有1-3位其他家庭成员的乘客有292人,占总人数的32.77%,幸存169人,幸存率57.88%
  • 有4位以上家庭成员的乘客有62人,占总人数的6.96%,幸存10人,幸存率16.13%

分析数据¶

In [49]:
lr_titanic_train = clean_train.copy()  # 备份数据集
lr_titanic_train.head()
Out[49]:
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Embarked HasCabin FamilyNum
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 S 0 1
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C 1 1
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 S 0 0
3 4 1 1 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 1 0 113803 53.1000 S 1 1
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.0500 S 0 0

删除无关特征:

  • 乘客的唯一ID(PassengerId):用于唯一标识用户,与用户是否幸存无相关关系
  • 乘客的姓名(Name):用户专属名称,与用户是否幸存无相关关系
  • 船票号(Ticket):船票的唯一标识,与用户是否幸存无相关关系
In [50]:
lr_titanic_train = lr_titanic_train.drop(['PassengerId', 'Name', 'Ticket'], axis=1)  # 删除'PassengerId'、'Name'和'Ticket'三列
lr_titanic_train.head()
Out[50]:
Survived Pclass Sex Age SibSp Parch Fare Embarked HasCabin FamilyNum
0 0 3 male 22.0 1 0 7.2500 S 0 1
1 1 1 female 38.0 1 0 71.2833 C 1 1
2 1 3 female 26.0 0 0 7.9250 S 0 0
3 1 1 female 35.0 1 0 53.1000 S 1 1
4 0 3 male 35.0 0 0 8.0500 S 0 0

虚拟变量构建:将所有分类变量构建位虚拟变量

  • 分类变量包含:Pclass、Sex、Embarked、HasCabin
In [51]:
lr_titanic_train = pd.get_dummies(lr_titanic_train, columns=['Pclass', 'Sex', 'Embarked', 'HasCabin'], dtype=int, drop_first=True)
lr_titanic_train.head()
Out[51]:
Survived Age SibSp Parch Fare FamilyNum Pclass_2 Pclass_3 Sex_male Embarked_Q Embarked_S HasCabin_1
0 0 22.0 1 0 7.2500 1 0 1 1 0 1 0
1 1 38.0 1 0 71.2833 1 0 0 0 0 0 1
2 1 26.0 0 0 7.9250 0 0 1 0 0 1 0
3 1 35.0 1 0 53.1000 1 0 0 0 0 1 1
4 0 35.0 0 0 8.0500 0 0 1 1 0 1 0

构造自变量与因变量:提取出自变量 X 和因变量 y,用于逻辑回归模型训练

In [52]:
y = lr_titanic_train['Survived']  # 提取出因变量列
y
Out[52]:
0      0
1      1
2      1
3      1
4      0
      ..
886    0
887    1
888    0
889    1
890    0
Name: Survived, Length: 891, dtype: category
Categories (2, int64): [0, 1]
In [53]:
X = lr_titanic_train.drop('Survived', axis=1)  # 把表示因变量的'Survived'列移除,其他列都是自变量列
X.head()
Out[53]:
Age SibSp Parch Fare FamilyNum Pclass_2 Pclass_3 Sex_male Embarked_Q Embarked_S HasCabin_1
0 22.0 1 0 7.2500 1 0 1 1 0 1 0
1 38.0 1 0 71.2833 1 0 0 0 0 0 1
2 26.0 0 0 7.9250 0 0 1 0 0 1 0
3 35.0 1 0 53.1000 1 0 0 0 0 1 1
4 35.0 0 0 8.0500 0 0 1 1 0 1 0

检查变量与变量间的相关性:

In [54]:
sns.heatmap(X.corr().abs(), annot=True)  # 用热力图直观展示变量间相关性的大小
plt.show()
No description has been provided for this image

由热力图可以看出:FamilyNum 和 SibSp 强相关

操作:移除 SibSp

In [55]:
X = X.drop(['SibSp'], axis=1)  # 删除强相关特征
X.head()
Out[55]:
Age Parch Fare FamilyNum Pclass_2 Pclass_3 Sex_male Embarked_Q Embarked_S HasCabin_1
0 22.0 0 7.2500 1 0 1 1 0 1 0
1 38.0 0 71.2833 1 0 0 0 0 0 1
2 26.0 0 7.9250 0 0 1 0 0 1 0
3 35.0 0 53.1000 1 0 0 0 0 1 1
4 35.0 0 8.0500 0 0 1 1 0 1 0

项目迭代:第一次模型训练后,发现 ‘Fare、Parch、Pclass_2、Embarked_Q’ 三个特征对模型没有显著预测效果,所以在此移除这三个特征

In [56]:
X = X.drop(['Fare', 'Parch', 'Pclass_2','Embarked_Q'], axis=1)  # 删除对模型无显著预测效果的特征
X.head()
Out[56]:
Age FamilyNum Pclass_3 Sex_male Embarked_S HasCabin_1
0 22.0 1 1 1 1 0
1 38.0 1 0 0 0 1
2 26.0 0 1 0 1 0
3 35.0 1 0 0 1 1
4 35.0 0 1 1 1 0

项目迭代:第二次模型训练后,发现模型效果仍不够理想,由于 ‘Embarked_S’ 特征对,对模型没有显著预测效果,所以在此移除这个特征

In [57]:
X = X.drop(['Embarked_S'], axis=1)  # 删除对模型无显著预测效果的特征【后加的】
X.head()
Out[57]:
Age FamilyNum Pclass_3 Sex_male HasCabin_1
0 22.0 1 1 1 0
1 38.0 1 0 0 1
2 26.0 0 1 0 0
3 35.0 1 0 0 1
4 35.0 0 1 1 0

自变量构建补充:为了保证截距不会被模型忽略,需要给自变量表格增加一个自变量列,其值全为 1

In [58]:
X = sm.add_constant(X)
X.head()
Out[58]:
const Age FamilyNum Pclass_3 Sex_male HasCabin_1
0 1.0 22.0 1 1 1 0
1 1.0 38.0 1 0 0 1
2 1.0 26.0 0 1 0 0
3 1.0 35.0 1 0 0 1
4 1.0 35.0 0 1 1 0

构建逻辑回归模型¶

In [59]:
model = sm.Logit(y, X)  # 建立模型
result = model.fit()  # 拟合模型
result.summary()  # 输出模型拟合结果
Optimization terminated successfully.
         Current function value: 0.440651
         Iterations 6
Out[59]:
Logit Regression Results
Dep. Variable: Survived No. Observations: 891
Model: Logit Df Residuals: 885
Method: MLE Df Model: 5
Date: Mon, 13 Apr 2026 Pseudo R-squ.: 0.3383
Time: 15:21:59 Log-Likelihood: -392.62
converged: True LL-Null: -593.33
Covariance Type: nonrobust LLR p-value: 1.470e-84
coef std err z P>|z| [0.025 0.975]
const 2.8511 0.345 8.254 0.000 2.174 3.528
Age -0.0376 0.008 -4.852 0.000 -0.053 -0.022
FamilyNum -0.2301 0.066 -3.501 0.000 -0.359 -0.101
Pclass_3 -1.2214 0.214 -5.716 0.000 -1.640 -0.803
Sex_male -2.7654 0.199 -13.907 0.000 -3.155 -2.376
HasCabin_1 1.2729 0.244 5.209 0.000 0.794 1.752

模型第一次拟合:

  1. 模型的 Pseudo R-squ = 0.3455,达到正常的拟合水平
  2. Fare 的 P 值为 0.392,说明 Fare 对模型没有显著预测效果,需要移除 Fare 特征
  3. Parch 的 P 值为 0.280,说明 Parch 对模型没有显著预测效果,需要移除 Parch 特征
  4. Pclass_2 的 P 值为 0.634,说明 Pclass_2 对模型没有显著预测效果,需要移除 Pclass_2 特征
  5. Embarked_Q 的 P 值为 0.815,说明 Embarked_Q 对模型没有显著预测效果,需要移除 Embarked_Q 特征

模型第二次拟合:

  1. 模型的 Pseudo R-squ = 0.3442,拟合水平少量提升。
  2. Embarked_S 的 P 值为 0.044,为提高模型精度,尝试移除 Embarked_S
  3. 其他剩余特征均对模型存在显著预测效果。

模型第三次拟合:

  1. 模型的 Pseudo R-squ = 0.3383,拟合水平再次提升。

模型结果总结¶

模型结果解读

In [60]:
print(f"年龄每增加1岁,生还几率降低 {(1-np.exp(-0.0376))*100:.2f}%")
print(f"每多1名同乘家庭成员,生还几率降低 {(1-np.exp(-0.2301))*100:.2f}%")
print(f"三等舱乘客的生还几率比一等舱乘客低 {(1-np.exp(-1.2214))*100:.2f}%")
print(f"男性乘客的生还几率比女性乘客低 {(1-np.exp(-2.7654))*100:.2f}%")
print(f"有登记船舱信息的乘客生还几率比无登记乘客高 {(np.exp(1.2729)-1)*100:.2f}%")
年龄每增加1岁,生还几率降低 3.69%
每多1名同乘家庭成员,生还几率降低 20.55%
三等舱乘客的生还几率比一等舱乘客低 70.52%
男性乘客的生还几率比女性乘客低 93.70%
有登记船舱信息的乘客生还几率比无登记乘客高 257.12%

总结:泰坦尼克号沉船事件中,乘客生还几率受年龄、家庭规模、船舱等级、性别以及是否有船舱记录影响显著

  • 年龄越大,生还几率越低:年龄每增加1岁,生还几率降低 3.69%
  • 家庭规模越大,生还几率越低:每多1名同乘家庭成员,生还几率降低 20.55%
  • 船舱越高级,生还几率越高:三等舱乘客的生还几率比一等舱乘客低 70.52%
  • 优先救援女性乘客:男性乘客的生还几率比女性乘客低 93.70%
  • 优先救援有登记船舱信息的乘客:有登记船舱信息的乘客生还几率比无登记乘客高 257.12%

使用逻辑回归模型¶

导入测试集数据¶

In [61]:
origin_test = pd.read_csv('test.csv')  # 读取测试集 CSV 文件
origin_test.head()
Out[61]:
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 892 3 Kelly, Mr. James male 34.5 0 0 330911 7.8292 NaN Q
1 893 3 Wilkes, Mrs. James (Ellen Needs) female 47.0 1 0 363272 7.0000 NaN S
2 894 2 Myles, Mr. Thomas Francis male 62.0 0 0 240276 9.6875 NaN Q
3 895 3 Wirz, Mr. Albert male 27.0 0 0 315154 8.6625 NaN S
4 896 3 Hirvonen, Mrs. Alexander (Helga E Lindqvist) female 22.0 1 1 3101298 12.2875 NaN S

对测试集数据进行预处理¶

In [62]:
clean_test = origin_test.copy()  # 将原始数据集复制一份,以防改错
clean_test.head()
Out[62]:
PassengerId Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 892 3 Kelly, Mr. James male 34.5 0 0 330911 7.8292 NaN Q
1 893 3 Wilkes, Mrs. James (Ellen Needs) female 47.0 1 0 363272 7.0000 NaN S
2 894 2 Myles, Mr. Thomas Francis male 62.0 0 0 240276 9.6875 NaN Q
3 895 3 Wirz, Mr. Albert male 27.0 0 0 315154 8.6625 NaN S
4 896 3 Hirvonen, Mrs. Alexander (Helga E Lindqvist) female 22.0 1 1 3101298 12.2875 NaN S

把已知的不需要用到的特征列删掉¶

In [63]:
clean_test = clean_test.drop(['Fare', 'PassengerId', 'Name', 'Ticket'], axis=1)
clean_test.head()
Out[63]:
Pclass Sex Age SibSp Parch Cabin Embarked
0 3 male 34.5 0 0 NaN Q
1 3 female 47.0 1 0 NaN S
2 2 male 62.0 0 0 NaN Q
3 3 male 27.0 0 0 NaN S
4 3 female 22.0 1 1 NaN S

评估剩下的特征¶

In [64]:
clean_test.info()
<class 'pandas.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 7 columns):
 #   Column    Non-Null Count  Dtype  
---  ------    --------------  -----  
 0   Pclass    418 non-null    int64  
 1   Sex       418 non-null    str    
 2   Age       332 non-null    float64
 3   SibSp     418 non-null    int64  
 4   Parch     418 non-null    int64  
 5   Cabin     91 non-null     str    
 6   Embarked  418 non-null    str    
dtypes: float64(1), int64(3), str(3)
memory usage: 23.0 KB

小结:

  1. Age 存在缺失
  2. Cabin 存在缺失
  3. Pclass(船舱等级)、Sex(性别)、Embarked(登船港口)都是分类特征,但这些特征的数据类型各异
In [65]:
clean_test['Age'] = clean_test['Age'].fillna(clean_test['Age'].mean())  # 用 Age 列数据的平均值填充 Age 列的 NaN 值
clean_test['Age'].isnull().sum()  # 验证 Age 列的 NaN 值是否已被填充
Out[65]:
np.int64(0)
In [66]:
# 构造一个新的列,有登记船舱信息记为1,无登记船舱信息记为0
clean_test['HasCabin'] = clean_test['Cabin'].notnull().astype("int")  # 构造出 HasCabin 列
clean_test[['Cabin','HasCabin']]
Out[66]:
Cabin HasCabin
0 NaN 0
1 NaN 0
2 NaN 0
3 NaN 0
4 NaN 0
... ... ...
413 NaN 0
414 C105 1
415 NaN 0
416 NaN 0
417 NaN 0

418 rows × 2 columns

In [67]:
clean_test['Pclass'] = clean_test['Pclass'].astype('category')  # 更改 Pclass 列
clean_test['Pclass']
Out[67]:
0      3
1      3
2      2
3      3
4      3
      ..
413    3
414    1
415    3
416    3
417    3
Name: Pclass, Length: 418, dtype: category
Categories (3, int64): [1, 2, 3]
In [68]:
clean_test['Sex'] = clean_test['Sex'].astype('category')  # 更改 Pclass 列
clean_test['Sex']
Out[68]:
0        male
1      female
2        male
3        male
4      female
        ...  
413      male
414    female
415      male
416      male
417      male
Name: Sex, Length: 418, dtype: category
Categories (2, str): ['female', 'male']
In [69]:
clean_test['Embarked'] = clean_test['Embarked'].astype('category')  # 更改 Pclass 列
clean_test['Embarked']
Out[69]:
0      Q
1      S
2      Q
3      S
4      S
      ..
413    S
414    C
415    S
416    S
417    C
Name: Embarked, Length: 418, dtype: category
Categories (3, str): ['C', 'Q', 'S']

构造新特征¶

In [70]:
clean_test["FamilyNum"] = clean_test["SibSp"] + clean_test["Parch"]  # 家庭成员人数 = 同伴或同胞数 + 父母或孩子数
clean_test.head(10)
Out[70]:
Pclass Sex Age SibSp Parch Cabin Embarked HasCabin FamilyNum
0 3 male 34.5 0 0 NaN Q 0 0
1 3 female 47.0 1 0 NaN S 0 1
2 2 male 62.0 0 0 NaN Q 0 0
3 3 male 27.0 0 0 NaN S 0 0
4 3 female 22.0 1 1 NaN S 0 2
5 3 male 14.0 0 0 NaN S 0 0
6 3 female 30.0 0 0 NaN Q 0 0
7 2 male 26.0 1 1 NaN S 0 2
8 3 female 18.0 0 0 NaN C 0 0
9 3 male 21.0 2 0 NaN S 0 2

把因变量的分类变量构造成虚拟变量¶

  • 由于要进行‘逻辑回归’,所以此处需要把所有因变量的分类变量构造成虚拟变量【Survived:是预测结果,不能改虚拟变量】
  • 分类变量包含:Pclass、Sex、Embarked、HasCabin
In [71]:
clean_test = pd.get_dummies(clean_test, columns=['Pclass', 'Sex', 'Embarked', 'HasCabin'], dtype=int, drop_first=True)
clean_test.head()
Out[71]:
Age SibSp Parch Cabin FamilyNum Pclass_2 Pclass_3 Sex_male Embarked_Q Embarked_S HasCabin_1
0 34.5 0 0 NaN 0 0 1 1 1 0 0
1 47.0 1 0 NaN 1 0 1 0 0 1 0
2 62.0 0 0 NaN 0 1 0 1 1 0 0
3 27.0 0 0 NaN 0 0 1 1 0 1 0
4 22.0 1 1 NaN 2 0 1 0 0 1 0

删除无关变量¶

In [72]:
clean_test = clean_test.drop(['SibSp', 'Parch', 'Cabin', 'Pclass_2', 'Embarked_Q', 'Embarked_S'], axis=1)
clean_test.head()
Out[72]:
Age FamilyNum Pclass_3 Sex_male HasCabin_1
0 34.5 0 1 1 0
1 47.0 1 1 0 0
2 62.0 0 0 1 0
3 27.0 0 1 1 0
4 22.0 2 1 0 0

为了保证截距不会被模型忽略,需要给自变量表格增加一个自变量列,其值全为 1¶

In [73]:
clean_test = sm.add_constant(clean_test)
clean_test.head()
Out[73]:
const Age FamilyNum Pclass_3 Sex_male HasCabin_1
0 1.0 34.5 0 1 1 0
1 1.0 47.0 1 1 0 0
2 1.0 62.0 0 0 1 0
3 1.0 27.0 0 1 1 0
4 1.0 22.0 2 1 0 0

再看一眼概览,确保数据集正确清洗完成¶

In [74]:
clean_test.info()
<class 'pandas.DataFrame'>
RangeIndex: 418 entries, 0 to 417
Data columns (total 6 columns):
 #   Column      Non-Null Count  Dtype  
---  ------      --------------  -----  
 0   const       418 non-null    float64
 1   Age         418 non-null    float64
 2   FamilyNum   418 non-null    int64  
 3   Pclass_3    418 non-null    int64  
 4   Sex_male    418 non-null    int64  
 5   HasCabin_1  418 non-null    int64  
dtypes: float64(2), int64(4)
memory usage: 19.7 KB

使用预处理后的测试集数据进行模型预测¶

In [75]:
result_test = result.predict(clean_test)  # 对测试集数据进行预测
result_test
Out[75]:
0      0.080819
1      0.409658
2      0.095998
3      0.104366
4      0.585002
         ...   
413    0.093425
414    0.934593
415    0.070340
416    0.093425
417    0.061072
Length: 418, dtype: float64

构建要上传到竞赛平台的结果数据集¶

  • PassengerID 列:存放原来的测试集的 PassengerID 列
  • Survived 列:存放预测结果【0:遇难】【1:幸存】
In [76]:
# 定义‘预测概率>0.61’为‘幸存’,否则为‘遇难’
result_test = result_test > 0.61  # 把预测结果转为布尔值
result_test = result_test.astype(int)  # 把预测结果的布尔值转为整数类型的0和1【0:遇难】【1:幸存】
result_test
Out[76]:
0      0
1      0
2      0
3      0
4      0
      ..
413    0
414    1
415    0
416    0
417    0
Length: 418, dtype: int64
In [77]:
# 构建测试结果 DataFrame
result_test_dataframe = pd.DataFrame({'PassengerId':origin_test['PassengerId'], 'Survived':result_test})
result_test_dataframe.head()
Out[77]:
PassengerId Survived
0 892 0
1 893 0
2 894 0
3 895 0
4 896 0

保存测试集的预测结果¶

In [78]:
result_test_dataframe.to_csv("result_test.csv", index=False)

泰坦尼克号幸存预测 Kaggle 竞赛网址:https://www.kaggle.com/competitions/titanic/overview

文件提交格式:

  • 提交一个恰好有418条条目加上一行头部的预测结果csv文件。
  • 该文件只能包含2列(PassengerId和Survived)

项目评分:0.77990

In [ ]: