kaggle比赛入门 - Spaceship Titanic (第四部分)

本文承接上一篇

1. 填补缺失值

分析 “Group”(乘客组)与 “Cabin”(舱位)之间的关系

# Joint distribution of Group and Cabin features
GCD_gb = data[data['Group_size']>1].groupby(['Group', 'Cabin_deck'])['Cabin_deck'].size().unstack().fillna(0)
GCN_gb = data[data['Group_size']>1].groupby(['Group', 'Cabin_number'])['Cabin_number'].size().unstack().fillna(0)
GCS_gb = data[data['Group_size']>1].groupby(['Group', 'Cabin_side'])['Cabin_side'].size().unstack().fillna(0)
  • 只保留 Group_size > 1 的乘客,即属于某个群组(Group)的乘客。单独旅行的乘客 (Group_size == 1) 会被排除。
  • .groupby([‘Group’, ‘Cabin_deck’])[‘Cabin_deck’].size() 计算每个 Group 在不同 Cabin_deck 的乘客数。
  • .unstack() 将 Cabin_deck 转为列索引
GCD_unique = (GCD_gb>0).sum(axis=1)
GCN_unique = (GCN_gb>0).sum(axis=1)
GCS_unique = (GCS_gb>0).sum(axis=1)
# Countplots
fig=plt.figure(figsize=(16,4))
plt.subplot(1,3,1)
sns.countplot(x=GCD_unique)
plt.title('#Unique cabin decks per group')

plt.subplot(1,3,2)
sns.countplot(x=GCN_unique)
plt.title('#Unique cabin numbers per group')

plt.subplot(1,3,3)
sns.countplot(x=GCS_unique)
plt.title('#Unique cabin sides per group')

fig.tight_layout()

在这里插入图片描述

# Missing values before
CS_bef = data['Cabin_side'].isna().sum()

# Passengers with missing Cabin side and in a group with known Cabin side
GCS_index = data[data['Cabin_side'].isna()][(data[data['Cabin_side'].isna()]['Group']).isin(GCS_gb.index)].index

# Fill corresponding missing values
data.loc[GCS_index, 'Cabin_side']=data.iloc[GCS_index,:]['Group'].map(lambda x: GCS_gb.idxmax(axis=1)[x])

# Print number of missing values left
print('#Cabin_side missing values before:', CS_bef)
print('#Cabin_side missing values after:', data['Cabin_side'].isna().sum())
  • data[‘Cabin_side’].isna().sum() 计算 Cabin_side 缺失的行数,存入变量 CS_bef。
  • 属于某个 Group,且该 Group 其他成员的 Cabin_side 已知(即 Group 存在于 GCS_gb.index 中)。
  • GCS_gb 之前计算了每个 Group 在不同 Cabin_side(左舷/右舷)的分布情况,所以这里确保该 Group 里至少有一个乘客的 Cabin_side 是已知的。
  • GCS_gb.idxmax(axis=1) 返回 每个 Group 最多成员所在的 Cabin_side
  • data[‘Group’].map(…) 查找该乘客所在 Group 的多数 Cabin_side,并填充到 Cabin_side 列。
#Cabin_side missing values before: 299
#Cabin_side missing values after: 162

计算姓氏 (Surname) 和舱位方向 (Cabin_side) 之间的联合分布,即 统计同姓乘客在不同舱位方向上的人数。

# Joint distribution of Surname and Cabin side
SCS_gb = data[data['Group_size']>1].groupby(['Surname', 'Cabin_side'])['Cabin_side'].size().unstack().fillna(0)
SCS_gb
  • 只考虑 Group_size 大于 1 的乘客,即 那些属于一个家庭或团体的乘客。
  • 计算 每个 Surname 在不同 Cabin_side 的人数。
  • 将 Cabin_side(第二级索引)转换为列名
  • 如果某个 Surname 只出现在 P 或 S,另一个方向可能会是 NaN。
  • 用 0 填充 NaN,表示该姓氏在该 Cabin_side 没有乘客。
    在这里插入图片描述
# Ratio of sides 
SCS_gb['Ratio'] = SCS_gb['P']/(SCS_gb['P']+SCS_gb['S'])

# Histogram of ratio
plt.figure(figsize=(10,4))
sns.histplot(SCS_gb['Ratio'], kde=True, binwidth=0.05)
plt.title('Ratio of cabin side by surname')
  • 该姓氏乘客在 P 舱位的比例,范围在 0 到 1 之间:
  • 0:该姓氏的所有乘客 都在 S(右舷)。
  • 1:该姓氏的所有乘客 都在 P(左舷)。
  • kde=True:绘制核密度估计曲线(KDE),显示数据的平滑分布。

在这里插入图片描述

SCS_gb

在这里插入图片描述

# Print proportion
print('Percentage of families all on the same cabin side:', 100*np.round((SCS_gb['Ratio'].isin([0,1])).sum()/len(SCS_gb),3), '%')
Percentage of families all on the same cabin side: 76.7 %

来自同一个家庭的乘客大部分都在舱板的同一侧。

SCS_gb.drop('Ratio', axis=1, inplace=True)
# Missing values before
CS_bef = data['Cabin_side'].isna().sum()

# Passengers with missing Cabin side and in a family with known Cabin side
SCS_index = data[data['Cabin_side'].isna()][(data[data['Cabin_side'].isna()]['Surname']).isin(SCS_gb.index)].index

# Fill corresponding missing values
data.loc[SCS_index, 'Cabin_side'] = data.iloc[SCS_index, :]['Surname'].map(lambda x: SCS_gb.idxmax(axis=1)[x])

# Print number of missing values left
print('#Cabin_side missing values before:', CS_bef)
print('#Cabin_side missing values after:', data['Cabin_side'].isna().sum())
  • 计算 Cabin_side 列中缺失值 (NaN) 的数量,存入 CS_bef 变量。
  • 选取 Cabin_side 为空 (NaN) 的乘客。
  • 获取这些乘客的姓氏 (Surname)。
  • 过滤出姓氏 (Surname) 在 SCS_gb 这个数据集中 的乘客。
  • SCS_gb.index 是之前计算的按姓氏 (Surname) 统计 Cabin_side 分布的表,只包含有 Cabin_side 信息的姓氏。

  • 获取索引 SCS_index 处乘客的 Surname。
  • SCS_gb.idxmax(axis=1) 找到 每个姓氏 (Surname) 最常见的 Cabin_side
  • 通过 Surname 查询该姓氏最常见的 Cabin_side 并填充。
#Cabin_side missing values before: 162
#Cabin_side missing values after: 66
# Drop surname, we don't need it anymore
data.drop('Surname', axis=1, inplace=True)
data['Cabin_side'].value_counts()
Cabin_side
S    6504
P    6400
Name: count, dtype: int64
# Missing values before
CS_bef = data['Cabin_side'].isna().sum()

# Fill remaining missing values with outlier
data.loc[data['Cabin_side'].isna(), 'Cabin_side'] = 'Z'

# Print number of missing values left
print('#Cabin_side missing values before:', CS_bef)
print('#Cabin_side missing values after:', data['Cabin_side'].isna().sum())
  • 将所有剩余的 Cabin_side 缺失值填充为 ‘Z’(表示异常值)
#Cabin_side missing values before: 66
#Cabin_side missing values after: 0

# Missing values before
CD_bef = data['Cabin_deck'].isna().sum()

# Passengers with missing cabin deck and in a group with known majority cabin deck
GCD_index = data[data['Cabin_deck'].isna()][(data[data['Cabin_deck'].isna()]['Group']).isin(GCD_gb.index)].index

# Fill corresponding missing values
data.loc[GCD_index, 'Cabin_deck'] = data.iloc[GCD_index, :]['Group'].map(lambda x: GCD_gb.idxmax(axis=1)[x])

# Print number of missing values left
print('#Cabin_deck missing values before:', CD_bef)
print('#Cabin_deck missing values after:', data['Cabin_deck'].isna().sum())
  • 统计 Cabin_deck 缺失值
  • data[‘Cabin_deck’].isna():找到 Cabin_deck 为空 (NaN) 的乘客。
  • data[data[‘Cabin_deck’].isna()][‘Group’]:获取这些乘客的 Group(分组信息)。
  • GCD_gb 是按 Group 和 Cabin_deck 计算的联合分布表,表示每个 Group 里不同 Cabin_deck 的出现次数。
  • 这里检查 Group 是否在 GCD_gb 里,如果是,说明该组的 Cabin_deck 有多数信息,可以填充。

  • 取出 GCD_index 对应行的 Group,即每个缺失 Cabin_deck 的乘客的组别。
  • 计算每个 Group 内出现最多的 Cabin_deck(即该组的多数甲板)
  • idxmax(axis=1) 找出 GCD_gb 每一行(即 Group)中数量最多的 Cabin_deck。
  • .map(…):用 Group 去查找对应的多数 Cabin_deck 并填充。
#Cabin_deck missing values before: 299
#Cabin_deck missing values after: 162

按照 HomePlanet(出发星球)、Destination(目的地)、Solo(是否独自旅行)分组,然后计算 Cabin_deck 的众数(mode,即最常见的值)

# Joint distribution
data.groupby(['HomePlanet', 'Cabin_deck'])['Cabin_deck'].size().unstack().fillna(0)

在这里插入图片描述

data.groupby(['HomePlanet', 'Solo', 'Cabin_deck'])['Cabin_deck'].size().unstack().fillna(0)

在这里插入图片描述

data.groupby(['HomePlanet', 'Destination', 'Solo', 'Cabin_deck'])['Cabin_deck'].size().unstack().fillna(0)

在这里插入图片描述

# Missing values before
CD_bef = data['Cabin_deck'].isna().sum()

# Fill missing values using the mode
na_rows_CD = data.loc[data['Cabin_deck'].isna(), 'Cabin_deck'].index

data.loc[data['Cabin_deck'].isna(), 'Cabin_deck'] = data.groupby(
    ['HomePlanet', 'Destination', 'Solo'])['Cabin_deck'].transform(
    lambda x: x.fillna(pd.Series.mode(x)[0]))[na_rows_CD]

# Print number of missing values left
print('#Cabin_deck missing values before:', CD_bef)
print('#Cabin_deck missing values after:', data['Cabin_deck'].isna().sum())
  • 找出 Cabin_deck 为空 (NaN) 的行索引,并存入 na_rows_CD,稍后用于选择填充数据。
  • 假设同一 HomePlanet 的旅客前往相同 Destination,且 Solo 状态相同,那么他们的 Cabin_deck 可能相似。
  • pd.Series.mode(x) 计算该组 Cabin_deck 的众数(mode)
  • [0] 取最常见的 Cabin_deck(如果有多个众数,取第一个)。
  • .fillna(…) 用该众数填充该组中的 NaN。
  • transform() 让填充后的数据保持原始数据的形状,不会丢失索引信息。
  • [na_rows_CD] 只选取原本缺失的行进行填充,防止影响已有数据。
#Cabin_deck missing values before: 162
#Cabin_deck missing values after: 0

利用 Group 预测 Cabin_number,利用线性回归拟合

# Scatterplot
plt.figure(figsize=(10,4))
sns.scatterplot(
    x=data['Cabin_number'], 
    y=data['Group'], 
    c=LabelEncoder().fit_transform(data.loc[~data['Cabin_number'].isna(), 'Cabin_deck']), 
    cmap='tab10'
)

plt.title('Cabin_number vs group coloured by group')
  • LabelEncoder().fit_transform(…) 将 Cabin_deck 转换为数值,这样 c 参数可以使用它来区分颜色。
  • 只选取 Cabin_number 非空的行,确保数据完整。
  • tab10 是 matplotlib 的颜色映射表,适用于分类数据(最多支持 10 种颜色)。

在这里插入图片描述

  • Cabin_number(舱位编号)和 Group(乘客组编号)在同一甲板(deck)上存在线性关系,因此可以使用线性回归来填补缺失的舱位编号。
cabin_deck_list
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'T']
cabin_deck_list_new = [x for x in cabin_deck_list if x != 'T']
cabin_deck_list_new
['A', 'B', 'C', 'D', 'E', 'F', 'G']
# Missing values before
CN_bef = data['Cabin_number'].isna().sum()

# Extrapolate linear relationship on a deck by deck basis
for deck in cabin_deck_list_new:
    X_CN = data.loc[~(data['Cabin_number'].isna()) & (data['Cabin_deck']==deck), 'Group']
    y_CN = data.loc[~(data['Cabin_number'].isna()) & (data['Cabin_deck']==deck), 'Cabin_number']
    X_test_CN = data.loc[(data['Cabin_number'].isna()) & (data['Cabin_deck']==deck), 'Group']

    # Linear regression
    model_CN = LinearRegression()
    model_CN.fit(X_CN.values.reshape(-1, 1), y_CN)
    preds_CN = model_CN.predict(X_test_CN.values.reshape(-1, 1))

    # Fill missing values with predictions
    data.loc[(data['Cabin_number'].isna()) & (data['Cabin_deck']==deck), 'Cabin_number'] = preds_CN.astype(int)

# Print number of missing values left
print('#Cabin_number missing values before:', CN_bef)
print('#Cabin_number missing values after:', data['Cabin_number'].isna().sum())
  • 遍历 cabin_deck_list_new,对 每个甲板(deck)单独拟合回归模型,确保不同甲板上的模式不会相互干扰。
  • 获取已知 Cabin_number 数据(作为训练集)
  • 获取缺失 Cabin_number 数据(作为测试集)
  • X_test_CN:对于 Cabin_number 为空的行,我们使用 Group 作为 X,以便用模型预测对应的 Cabin_number。
  • X_CN.values.reshape(-1,1):转换 X_CN 为二维数组,适应 scikit-learn 训练格式
  • 用预测的 Cabin_number 填补缺失值
#Cabin_number missing values before: 299
#Cabin_number missing values after: 0
# One-hot encode cabin regions
data['Cabin_region1'] = (data['Cabin_number']<300).astype(int) 
data['Cabin_region2'] = ((data['Cabin_number']>=300) & (data['Cabin_number']<600)).astype(int)
data['Cabin_region3'] = ((data['Cabin_number']>=600) & (data['Cabin_number']<900)).astype(int)
data['Cabin_region4'] = ((data['Cabin_number']>=900) & (data['Cabin_number']<1200)).astype(int)
data['Cabin_region5'] = ((data['Cabin_number']>=1200) & (data['Cabin_number']<1500)).astype(int)
data['Cabin_region6'] = ((data['Cabin_number']>=1500) & (data['Cabin_number']<1800)).astype(int)
data['Cabin_region7'] = (data['Cabin_number']>=1800).astype(int)
data.head()

在这里插入图片描述

下一篇继续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值