Kaggle:Titanic《泰坦尼克号》你的第一次竞赛

创作灵感

        博主,目前是一名在校大学生,因为在之前的学习过程中并没有深入学习,导致学习的知识并没有形成体系,很多东西都是一知半解,什么都会一点,但并不会熟练运用,所以我将回顾之前的学习内容,并和想在这方面一起学习和深入的同学一起进步。

        kaggle平台上的Titanic竞赛项目就是一个很好的学习项目,很适合没有或参加竞赛项目很少,编写代码能力不是很强,没有或接触数据分析、机器学习很少的同学。

        这是我第一次写博客,所写内容只表达个人意见和分享,所以如有错误,遗漏还请指正!大家一同进步。

        本文旨在帮助你在kaggle进行竞赛,并实现你的第一个项目。默认你已具有一定的代码基础,当然本文也会列出一些代码注解。

kaggle平台

        Kaggle 是一个面向数据科学和机器学习爱好者的在线平台,它提供了丰富的资源和工具,帮助用户学习、实践和交流:

核心功能:

  • 竞赛: Kaggle 最出名的是其举办的机器学习竞赛。来自世界各地的公司和组织会发布真实世界的问题和数据集,并提供奖金吸引数据科学家们参与竞争,解决这些问题。

  • 数据集: Kaggle 提供了大量的公开数据集,涵盖各个领域,可以用于学习和研究。

  • Notebook: Kaggle 提供了在线的 Jupyter Notebook 环境,用户可以直接在平台上进行数据分析和建模,无需本地配置环境。

  • 讨论区: Kaggle 拥有活跃的社区,用户可以在这里提问、分享经验、交流想法。

  • 课程: Kaggle 提供了多种数据科学和机器学习的在线课程,帮助用户学习新的技能。

如果你还没有注册过kaggle,那么请先注册,详细步骤不在此列出。

附上链接: 

Kaggle: Your Home for Data Scienceicon-default.png?t=N7T8https://www.kaggle.com/

正式开始

一.参加比赛

        第一件要做的事就是参加比赛!打开一个新窗口 the competition page, 然后点击 "Join Competition" 按钮。然后你会被带到规则界面,这里介绍了关于比赛的一些规则。

        竞赛的内容是希望你使用泰坦尼克号乘客的数据(姓名、年龄、票价等)来预测谁会幸存,谁会死亡。

二.数据集概览

        在竞赛界面可以找到data界面来查看比赛数据,共有三个数据文件(1) train.csv, (2) test.csv, (3) gender_submission.csv。

        你也可以下载这些数据集在本地进行分析。

        

(1) train.csv

train.csv 包含船上乘客子集的详细信息。包括姓名、年龄、车票等。

而第二列中的值(Survived)很重要可用于确定每位乘客是否幸存:

  • "1"代表乘客幸存.
  • "0"代表乘客死亡.

例如,在train.csv中列出的第一位乘客是Mr. Owen Harris。他死在泰坦尼克号上时只有22岁。

(2) test.csv

test.csv文件中的数据表现形式几乎与train.csv文件中一致,但缺少了Survived列,所以我们需要预测船上的其他418名乘客(test.csv中)是否幸存。

(3) gender_submission.csv

比赛提供的gender_submission.csv文件是一个示例,显示了应该如何构建预测并提交。它包含了PassengerId和Survived两列。所以就像这个文件一样,我们的提交应该具有:

  • "PassengerId" 列,包含test.csv中每个乘客的id。
  • "Survived" 列,其中“1”表示我们预测乘客幸存的行,“0”表示我们预测乘客死亡的行。

        上面是我们通过数据文件直接观察数据的构成,接下来,我将通过代码来对数据进行分析了解和预测。

三.开始编程

        首先要做的是创建一个Kaggle Notebook,其类似于jupter notebook,但并不需要在你的计算机上安装任何内容,你还可以利用kaggle平台上的GPU来加速你的训练过程。

这就是创建完之后的样子,数据集已经自动导入,我将它命名为Titanic test1.

        接下来就可以在里面进行编程了,下面的操作默认在Kaggle Notebook中进行编写。

(1)导入包

import re
import numpy as np
import pandas as pd
import plotly.express as px
from sklearn.impute import KNNImputer
from sklearn.cluster import KMeans
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from hyperopt import fmin, tpe, hp, Trials
from xgboost import XGBClassifier

(2)数据集加载和初步分析

#加载数据并对数据进行初步分析
train_data = pd.read_csv("/kaggle/input/titanic/train.csv")
test_data = pd.read_csv("/kaggle/input/titanic/test.csv")
#合并训练、测试集数据
alldata = pd.concat([train_data, test_data], axis = 0, ignore_index = True)

        这里使用pandas中的 read_csv()函数从CSV 文件中读取数据并将其存储在一个 DataFrame (train_data)对象中,括号内为文件路径。

       为了方便后续操作,我将对训练集和测试集数据进行合并。

        接下来我们对数据进行查看和初步了解。

train_data.head()

test_data.head()

alldata.info()

        使用info()方法对整体数据信息进行显示,可以观察到数据列名,类型、是否存在缺失值及所占大小。发现数据中Age、Fare、Cabin、Embarked列存在缺失值,接下来,我将对这些数据进行更进一步分析。

print(f"训练集有{len(train_data)}个样本数据,测试集有{len(test_data)}样本数据")
print(f"总共有{len(alldata)}个样本数据")

        这是数据中包含的特征信息含义。

 (3)数据描述性统计分析

#对样本数值数据进行更详细观察,得出其分布特征
round(train_data.describe(percentiles=[.5, .6, .7, .8,.9,]),2)

        使用describe方法对训练集数据进行描述性统计分析,可以显示计数、均值、标准差、最小值、最大值以及四分位数 (25%, 50%, 75%)信息。为了方便观察,使用round函数对数据进行四舍五入。

  • 计数 (count): 每列非缺失值的數量。例如,Age 列有 714 个非缺失值。

  • 平均值 (mean): 每列数值的平均值。例如,平均年龄为 29.70 岁。

  • 标准差 (std): 每列数值的标准差,反映数值的离散程度。例如,年龄的标准差为 14.53,说明年龄分布比较分散。

  • 最小值 (min): 每列数值的最小值。例如,最小年龄为 0.42 岁。

  • 50% (中位数): 每列数值的中位数,例如年龄的中位数为 28.00 岁。

  • 其他百分位数: 例如,90% 的乘客年龄低于 50.00 岁,说明存在一小部分年龄较大的乘客。

  • 最大值 (max): 每列数值的最大值。例如,最大年龄为 80.00 岁。

#对样本类别数据进行更详细观察,得出其分布特征,O即object
train_data.describe(include=['O'])

  • count: 每列非缺失值的数量。例如,Cabin列只有 204个非缺失值,缺失数据过多,所以在后续操作中,考虑将Cabin列数据删除。

  • unique: 每列唯一值的数量。例如,Embarked 列有 3 个唯一值,说明乘客分别来自于3个港口。

  • top: 每列出现频率最高的元素。例如,Sex 列出现频率最高的元素是 "male"。

  • freq: 每列出现频率最高的元素出现的次数。例如,"male" 出现了 577 次。

#对一些类别特征进行进一步分析,观察其与是否生存之间的相关程度
train_data[['Pclass','Survived']].groupby(['Pclass']).mean().sort_values(by='Survived', ascending=False)

 

train_data[['Sex','Survived']].groupby(['Sex']).mean().sort_values(by='Survived', ascending=False)

train_data[['SibSp','Survived']].groupby(['SibSp']).mean().sort_values(by='Survived', ascending=False)

train_data[['Parch','Survived']].groupby(['Parch']).mean().sort_values(by='Survived', ascending=False)

train_data[['Embarked','Survived']].groupby(['Embarked']).mean().sort_values(by='Survived', ascending=False)

         观察后,发现票务等级和性别与是否生还有较强的关联,而乘客父母兄弟配偶子女数量,在某方面与是否生还关联性过低,所以后续单独分析。

#对一些类别数据使用plotly来进行简单的可视化
fig = px.scatter(train_data, x="Age", y="Fare", color="Survived", 
                 hover_data=['Sex', 'Pclass'],
                 title="Titanic乘客生还分布图")

fig.show()

 

(4)数据预处理

        1.处理Name数据

        参考kaggle平台中一些前辈的经验,并进行解析。

        提取乘客姓名中的称谓,来建立新特征,因为称谓中蕴含着很多隐含信息,可以侧面反映,乘客的年龄、性别、社会地位信息等,提高模型的预测能力,并帮助后续的填充缺失值操作。

#提取乘客称谓到title中
alldata['title'] = alldata.Name.apply(lambda x: re.search(r',\s(.+?)\.', x).group(1))

        使用lambda 函数接受乘客姓名,r',\s(.+?)\.'为正则表达式,.group(1)返回称谓。

#统计title称谓计数
alldata.title.value_counts()

 

        使用.value_counts()方法进行计数。 

fig = px.scatter(alldata, x="title", y="Age", color="Sex",
                 title="年龄、姓氏、性别分布图")
fig.show()

        根据这些称谓的含义,对这些信息进行整合, 如将Ms(未知婚姻状况的女性)和Mlle(法语中代表未婚女性)整合到Miss(未婚女性)中;将一些带有社会地位的称谓,如Major、Lady等整合为稀有称谓,而如Master(未成年男性)单独列出,因为这是一种未成年男性的常见称谓,具有一定比例,且还可以表现出未成年人和成年人生还概率间差别,儿童通常具有更高的生还概率。

#整合称谓信息
alldata.loc[alldata.title.isin(['Ms', 'Mlle']), 'title'] = 'Miss'
alldata.loc[alldata.title.isin(['Mme']), 'title'] = 'Mrs'
rare = ['Major', 'Lady', 'Sir', 'Don', 'Capt', 'the Countess', 'Jonkheer', 'Dona', 'Dr', 'Rev', 'Col']
alldata.loc[alldata.title.isin(rare), 'title'] = 'rare'
alldata.title.value_counts()

#删除Name数据
alldata.drop(['Name'], axis = 1, inplace = True)
       2.处理SibSp、Parch、Ticket数据

        因为在之前的分析中,乘客的父母、配偶、子女、兄弟姐妹数量在某方面与生还概率关联性过低,所以在这里对特征进行处理,提取新特征,家庭人数、相同船票团体、团体人数、是否独自一人。这些特征是对原有特征的进一步扩充,也会对接下来操作起到帮助。

#提取新特征
alldata['family_size'] = alldata.SibSp + alldata.Parch + 1
alldata['ticket_group_count'] = alldata.groupby('Ticket')['Ticket'].transform('count')
alldata['group_size'] = alldata[['family_size', 'ticket_group_count']].max(axis = 1)
alldata['is_alone'] = alldata.group_size.apply(lambda x: 1 if x == 1 else 0)
       3.处理票价数据

        绘图观察票务等级和票价的分布,发现这样的分布不是很正常,因为有一部分乘客具有相同的船票,所以我们对票价进行处理,具有相同船票的乘客分摊票价,然后根据票务等级,对不同票务等级票价缺失值进行填充。

fig = px.scatter(alldata, x="Pclass", y="Fare", color="Pclass",
                 title="票价,等级分布图")
fig.show()

#提取新特征,并填充缺失值
alldata['fare_p'] = alldata.Fare / alldata.ticket_group_count
alldata.loc[alldata[alldata.fare_p.isna()].index, 'fare_p'] = alldata.groupby('Pclass')['fare_p'].median()[3]

        这是处理后票价的分布图,看起来比刚才好了一些,但发现一些人的票价为0?这是为什么,经过查询,可能这些人是工作人员,可能是受邀的嘉宾,又或者是一些赠票?这些数据极少,所以我们不对其进一步分析。

alldata.drop('Fare', axis = 1, inplace = True)
alldata.drop('Ticket', axis = 1, inplace = True)
       4.处理港口缺失数据

        这是那两个缺失值,根据前辈的经验和查询,我们找到了那两个缺失值,并进行填充。

        Martha Evelyn Stone : Titanic Survivor (encyclopedia-titanica.org)

alldata[alldata.Embarked.isnull()]

alldata.loc[alldata.Embarked.isnull(), 'Embarked'] = 'S'
       5.独热编码

        接下来,让我们对这些类别特征进行独热编码, 避免数值对模型的干扰。

preprocessing_dummies = pd.get_dummies(alldata[['Pclass', 'Sex', 'Embarked', 'title']],
               columns = ['Pclass', 'Sex', 'Embarked', 'title'],
               prefix = ['pclass', 'sex', 'embarked', 'title'],
               drop_first= False
              )
alldata = pd.concat([alldata, preprocessing_dummies], axis = 1)

        使用pd.get_dummies()进行独热编码,再使用pd.concat()将编码后数据连接到整体数据中。 

alldata.drop(['Pclass', 'Sex', 'Embarked', 'title'], axis = 1, inplace = True)
       6.处理Age数据

        在这里我们利用现有数据的一些特征,使用k近邻算法对年龄的缺失值进行填充。

imputer = KNNImputer(n_neighbors=4)
features = ['SibSp', 'Parch', 'Age',
       'family_size', 'ticket_group_count', 'group_size', 'is_alone',
       'fare_p', 'pclass_1', 'pclass_2', 'pclass_3',
       'sex_female', 'sex_male', 'embarked_C', 'embarked_Q', 'embarked_S',
       'title_Master', 'title_Miss', 'title_Mr', 'title_Mrs', 'title_rare']
all_data_filled = pd.DataFrame(imputer.fit_transform(alldata[features]), columns=features)
alldata['Age'] = all_data_filled['Age']

        接下来对,年龄数据进行处理,根据k均值聚类,对年龄特征进行分组,建立新特征。

        我将年龄数据分为4段。

#k均值聚类
kmeans = KMeans(n_clusters = 4, random_state = 41)
labels_pred = kmeans.fit_predict(alldata[['Age']])
# 获取聚类中心,返回每段年龄平均值。
kmeans.cluster_centers_.flatten()

         观察聚类后的排序索引。

np.argsort(kmeans.cluster_centers_.flatten())

        将原始索引进行重新映射。

label_dict = {label: v for v, label in enumerate(np.argsort(kmeans.cluster_centers_.flatten()))}
label_dict

        将排好序的labels标签赋值给Age_category。 

labels = [label_dict[label] for label in labels_pred]
alldata['Age_category'] = labels

        对分组后的年龄分布进行可视化。 

fig = px.scatter(alldata, x="Age_category", y="Age", color="Age_category",
                 title="年龄分布图")
fig.show()

alldata.drop(['PassengerId', 'Cabin', 'Age'], axis = 1, inplace = True)
        7.查看处理后数据信息
alldata.info()

        8.对整体数据再处理,划分数据集
train_clean = alldata.loc[alldata.Survived.notnull()].copy()
test_clean = alldata.loc[alldata.Survived.isnull()].drop('Survived', axis = 1).copy()
X = train_clean.drop('Survived', axis = 1)
y = train_clean.Survived
features = ['family_size', 'group_size', 'is_alone', 'Age_category','ticket_group_count',
       'pclass_1', 'pclass_2', 'pclass_3', 'sex_female', 'sex_male',
       'embarked_C', 'embarked_Q', 'embarked_S', 'title_Master', 'title_Miss',
       'title_Mr', 'title_Mrs', 'title_rare', 'fare_p']
X = X[features].copy()
#划分训练集,验证集
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=41) 

(5)模型及预测 

        使用xgboost模型,利用贝叶斯优化进行模型预测。

def objective(params):
    # 创建 XGBoost 模型,并将 params 作为模型参数
    model = XGBClassifier(**params)
    # 进行交叉验证,计算 AUC
    cv_results = cross_val_score(model, X_train, y_train, cv=10, scoring='roc_auc')
    return cv_results.mean()

# 定义搜索空间
space = {
    'n_estimators': hp.randint('n_estimators', 100, 201),
    'max_depth': hp.randint('max_depth', 4, 7),
    'learning_rate': hp.uniform('learning_rate', 0.1, 1),
    'gamma': hp.uniform('gamma', 0, 5),
    'subsample': hp.uniform('subsample', 0.5, 1),
    'colsample_bytree': hp.uniform('colsample_bytree', 0.5, 1),
    'min_child_weight': hp.quniform('min_child_weight', 1, 10, 1),
}
# 运行贝叶斯优化
trials = Trials()
#最佳参数
best_params = fmin(objective, space, algo=tpe.suggest, max_evals=200, trials=trials)
print(best_params)

  • n_estimators: 树的数量,范围为 [100, 201)。

  • max_depth: 树的最大深度,范围为 [4, 9)。

  • learning_rate: 学习率,范围为 [0.1, 1]。

  • gamma: 控制模型正则化的参数,范围为 [0, 5]。

  • subsample: 训练每棵树时使用的样本比例,范围为 [0.5, 1]。

  • colsample_bytree: 训练每棵树时使用的特征比例,范围为 [0.5, 1]。

  • min_child_weight: 控制叶节点最小样本权重的参数,范围为 [1, 10],步长为 1。

best_model = XGBClassifier(**best_params)
best_model.fit(X_train, y_train)
y_pred = best_model.predict(X_val)  # 使用测试集进行预测
accuracy = accuracy_score(y_val, y_pred)
print("Accuracy:", accuracy)

        1.XGBoost 模型解析 

XGBoost (Extreme Gradient Boosting) 是一种强大的梯度提升算法。它具有以下特点:

1. 梯度提升树 (Gradient Boosting Tree)
  • XGBoost 属于集成学习方法,它将多个弱学习器 (决策树) 组合成一个强学习器。

  • 它使用梯度下降算法来最小化损失函数,并利用前一棵树的预测结果来构建下一棵树。

  • 这种方式可以逐步减小模型的误差,最终获得高精度的预测结果。

2. 正则化 (Regularization)
  • XGBoost 引入了 L1 和 L2 正则化,防止模型过拟合。

  • L1 正则化可以使模型的权重趋向于 0,从而减少特征数量。

  • L2 正则化可以使模型的权重更小,提高模型的泛化能力。

3. 树结构优化 (Tree Structure Optimization)
  • XGBoost 使用了一种称为“树结构优化”的技术,来选择最佳的分裂点和最佳的树结构。

  • 它会根据损失函数的变化来评估不同分裂点的效果,并选择最优的分裂点。

  • 这种方法可以有效地减少树的深度,避免过拟合。

4. 并行化 (Parallelism)
  • XGBoost 支持并行计算,可以加速模型训练。

  • 它可以将训练数据划分成多个子数据集,并在不同的处理器上同时训练多个树。

  • 这使得 XGBoost 能够快速处理大规模数据集。

5. 优势
  • 高精度:XGBoost 往往能取得比其他模型更高的精度。

  • 抗过拟合:正则化和树结构优化可以有效地防止过拟合。

  • 可解释性:XGBoost 的决策树结构比较直观,易于理解。

  • 适用性广:XGBoost 可以用于分类、回归、排序等各种机器学习任务。

6. 缺点
  • 训练时间长:XGBoost 的训练时间可能较长,尤其是对于大型数据集。

  • 需要调参:XGBoost 的参数比较多,需要仔细调参才能获得最佳性能。

        2.正式提交 
test_pred = best_model.predict(test_clean[features])
pd.DataFrame({
     'PassengerId': test_data.PassengerId,
     'Survived' : test_pred
 }).to_csv('submission.csv', index = False)

总结

        最终提交的得分为0.79665(前5%)左右,你可以通过调整参数来提高分数,你也可以通过自己所学知识加以改进,比如,试着提取更多可用特征、填充数据时采用更多模型和特征加以对比学习、尝试更好的参数优化方法、训练模型时采用多种模型进行整合训练等。本篇文章参考了很多kaggle中前辈的经验,在这里列出一些文章,还有一些没有找到,你可以根据原文进行学习。

Surviving the Titanic with a Score of 0.811 (kaggle.com)

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

最爱吃土豆丝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值