Advertisement

Kaggle泰坦尼克号生存预测挑战——数据分析代码实现

阅读量:

Kaggle泰坦尼克号生存预测挑战

这是Kaggle上的Beginner’s Guide to Predictive Modeling Challenge(简称‘Getting Started’系列),它属于Beginner-level的比赛项目之一。我曾获得过该赛事的前8%名次,并打算通过系统复习与强化训练来进一步提升自己的技术能力。这次回顾将分为三个主要部分:

先修知识

  • numpy
  • pandas
  • matplotlib
  • seaborn
  • sklearn

**赛题地址:[ Titanic: Machine Learning from Disaster

](https://www.kaggle.com/c/titanic) **

泰坦尼克号的沉没

根据普遍认定,在她的处女航中

令人遗憾的是,在灾难发生时由于救生设备数量不足而导致沉船事件造成了重大人员伤亡结果:船上有共计2,224名乘客及船员成员共计1,502人遇难。尽管存在一些运气因素,并非所有人都具有同等的生存几率

在这一挑战中,参与者将被要求设计一个预测模型以探索哪些因素可能影响生存结果.该模型将基于乘客数据包括姓名年龄性别以及SocioeconomicClass等特征

任务分析 :这是一个分类任务,建立模型预测幸存者

数据集

  • 训练集:891*12,含891个样本,11+1个特征(一个是target)
  • 测试集:418*11,含418个样本,11个特征

Overview:

  • PassengerId:乘客编号 —— 编号意义不大,可能删除
    • Survived:存活标记(目标变量) —— 标签定义:1表示存活者, 0表示未幸存者
    • Pclass:舱位等级划分 —— 分为一等、二等、三等舱
    • Name:姓名信息 —— 虽然外国姓氏存在高低贵贱之分, 但姓名本身仍具参考价值
    • Sex:性别信息 —— 女士优先考虑吗??
    • Age:年龄分布情况 —— 年轻人是否更易生存??
    • SibSp:兄弟姐妹及配偶数量(泰坦尼克号上)—— 待进一步调查
    • Parch:父母及子女数量(泰坦尼克号上)—— 待进一步调查
    • Ticket:票务信息(待进一步调查)—— 票价尚待评估
    • Fare票价水平—— 高票价是否意味着更高待遇?
    • Cabin舱位类别—— 不同舱室可能影响逃生机会
    • Embarked登船地点—— C=查尔顿堡;Q=克伦伯格;S=哈德斯福

代码实现

导入相关的库
复制代码
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    import warnings
    warnings.filterwarnings('ignore')
    seed =2020
数据概览
复制代码
 加载数据方法 :pd.read_csv(),pd.read_table() 
    
    * pd.read_csv():读取以‘,’分割的文件到DataFrame,用于读取csv文件(csv用逗号符分隔字符段) 
    * pd.read_table():读取以‘\t’分割的文件到DataFrame,用于读取tsv文件(tsv用制表符分隔字符段) 
    * 实质上两个方法都是通用的,函数中参数sep可以选定分隔符的类型

例如用read_csv()读取tsv文件,df = pd.read_csv(file_path,sep='\t')

复制代码
 处理大型文件或内存不足时,采用分块读取方式: 
    
    * 使用参数chunksize指定文件块的大小(用于迭代)

使用pandas库中的read_csv方法从指定路径file_path中以每100行为一批加载数据。
依次遍历df中的每个元素i。
##用循环的方式即可迭代读取DataFrame

复制代码
 更多常用参数 ![在这里插入图片描述]()
复制代码
    ##加载数据  不建议把特征名转成中文,在画图时可能出现乱码
    train_df = pd.read_csv('data_train.csv')
    test_df = pd.read_csv('data_test.csv')
    ##数据预览 查看前5行的数据
    train_df.head()
在这里插入图片描述
复制代码
    test_df.head()
在这里插入图片描述
  • DataFrame.info():用于提供数据的基本概述以及包括有效样本数量、字段的数据类型等关键信息。
    • DataFrame.describe():用于提供数值型字段的统计信息。
复制代码
    train_df.info()
在这里插入图片描述
复制代码
    train_df.describe()
在这里插入图片描述
复制代码
    test_df.info()
在这里插入图片描述
复制代码
    test_df.describe()
在这里插入图片描述

数据的探索性分析EDA

复制代码
    ### 可以根据自己的需求封装一个函数
    def _data_info(data,categorical_features):
        print('number of train examples = {}'.format(data.shape[0]))
        print('number of train Shape = {}'.format(data.shape))
        print('Features={}'.format(data.columns))
        print('\n--------输出类别特征的种类--------')
        for i in categorical_features:
            if i in list(data.columns):
                print("train:"+i+":",list(data[i].unique()))
        print('\n--------缺失值--------')
        missing = data.isnull().sum()
        missing = missing[missing > 0]
        print(missing)
        missing.sort_values(inplace=True)
        missing.plot.bar()
        plt.show()
    def data_info(data_train,data_test,categorical_features):
        print('--------训练集基本概况--------')
        _data_info(data_train,categorical_features)
        print('\n\n--------测试集基本概况--------')
        _data_info(data_test,categorical_features)
数据概况、类别特征、缺失值情况

训练集的样本数:891, 特征数:11+1(一个标签)

测试集的样本数:418, 特征数:11(一个标签)

类别特征的情况:

复制代码
 Survived (标签): 取值{0,1},对应未幸存和幸存 
    2. Pclass: 取值{1,2,3},对应船舱级别 
    3. Sex: 取值{male,female},对应性别 
    4. Cabin: 船舱号 
    5. Embarked:取值{S,C,Q}。对应登船港口
复制代码
    data_info(train_df,test_df,['Survived','Pclass','Sex','Cabin','Embarked','SibSp','Parch'])

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

缺失值情况

了解了缺失值的情况后,可以对其进行简单的填充

复制代码
 训练集缺失值:

Age : 177

Cabin: 687

Embarked: 2

复制代码
2. 测试集缺失值:418

Age:86

Fare : 1

Cabin : 327

复制代码
    #将数据合并一起处理,添加一个train特征用于区分训练集和测试集
    train_df['train'] = 1
    test_df['train'] = 0
    data_df = pd.concat([train_df,test_df],sort=True).reset_index(drop=True)
    ## 删除PassengerId特征
    data_df.drop('PassengerId',inplace=True,axis=1)
    
    ## 先将非数字的类别特征数字化
    from sklearn import preprocessing
    ler_sex = preprocessing.LabelEncoder()
    ler_sex.fit(data_df['Sex'])
    data_df['Sex'] = ler_sex.transform(data_df['Sex'])
Embarked

缺失数量少,考虑使用众值进行填充

复制代码
    data_df['Embarked'].fillna(data_df['Embarked'].mode()[0],inplace=True)
    ## 填充完Embarker后,先将非数字的类别特征数字化
    ler_Embarked = preprocessing.LabelEncoder()
    ler_Embarked.fit(data_df['Embarked'])
    data_df['Embarked'] = ler_Embarked.transform(data_df['Embarked'])
Age

177 + 86 891 + 418 ≈ 20 % {177+86\over891+418}\approx 20% 8 9 1 + 4 1
8 1 7 7 + 8 6 ​ ≈ 2 0 %

缺失比例约为20%,考虑到对齐操作的必要性。
若仅依赖数据集自身所具有的特征来进行补全操作,则可能会达不到预期的效果。

通过利用其他聚合特征对Age进行填补,并通过相关性程度的分析可以看出,在Pclass这一特征的影响程度上更为显著。

复制代码
    abs(data_df.corr()['Age']).sort_values(ascending=False)
复制代码
    Age         1.000000
    Pclass      0.408106
    SibSp       0.243699
    Fare        0.178740
    Parch       0.150917
    Embarked    0.080195
    Survived    0.077221
    Sex         0.063645
    train       0.018528
年龄分布
复制代码
    y = data_df['Age']
    plt.figure(1)
    plt.title('Distribution of Age')
    sns.distplot(y, kde=True)
    
    ## 不同性别的年龄分布,可以看出他们的分布趋于相同
    plt.figure(2);
    Age_Sex0 = data_df.loc[data_df['Sex']==0,'Age']
    Age_Sex1 = data_df.loc[data_df['Sex']==1,'Age']
    plt.title('Distribution of Age in Sex');
    plt.legend(['Sex0','Sex1']);
    sns.distplot(Age_Sex0, kde=True);
    sns.distplot(Age_Sex1, kde=True);
在这里插入图片描述
不同Pclass中的年龄分布,从其中的分布确实能看出有一些差别
复制代码
    Age_p1 = data_df.loc[data_df['Pclass']==1,'Age']
    Age_p2 = data_df.loc[data_df['Pclass']==2,'Age']
    Age_p3 = data_df.loc[data_df['Pclass']==3,'Age']
    sns.distplot(Age_p1,kde=True,color='b')
    sns.distplot(Age_p2,kde=True,color='green')
    sns.distplot(Age_p3,kde=True,color='grey')
    plt.title('Distribution of Age in Pclass')
    plt.legend(['p1','p2','p3'])
在这里插入图片描述
复制代码
    Age_Pclass = data_df.groupby([ 'Pclass']).median()['Age']
    for pclass in range(1, 4):
        print('Median age of Pclass {}: {}'.format(pclass,Age_Pclass [pclass]))
    print('Median age of all passengers: {}'.format(data_df['Age'].median()))
    
    # 根据Pclass填充Age值
    data_df['Age'] = data_df.groupby(['Pclass'])['Age'].apply(lambda x: x.fillna(x.median()))
Fare

Fare缺失的样本只有一个,可以考虑直接用数据集的统计特征填充

但观察到SibSp和Parch均为零值时,则表明旅客购买了单人票,并且旅客舱位等级属于经济舱等级,在这种情况下,则可以考虑将这些属性进行整合

复制代码
    #查看Fare缺失的样本
    data_df[data_df['Fare'].isnull()]
在这里插入图片描述
复制代码
    ## Pclass对价格的影响很大
    abs(data_df.corr()['Fare']).sort_values(ascending=False)
复制代码
    Fare        1.000000
    Pclass      0.558629
    Survived    0.257307
    Embarked    0.238005
    Parch       0.221539
    Age         0.202512
    Sex         0.185523
    SibSp       0.160238
    train       0.030831
复制代码
    ## 聚合数据属性
    print(data_df.groupby(['Pclass', 'Parch','SibSp','Embarked']).Fare.max()[3][0][0][0])#18.7875
    print(data_df.groupby(['Pclass', 'Parch','SibSp','Embarked']).Fare.min()[3][0][0][0])#4.0125
    print(data_df.groupby(['Pclass', 'Parch','SibSp','Embarked']).Fare.median()[3][0][0][0])#7.2292
    print(data_df.groupby(['Pclass', 'Parch','SibSp','Embarked']).Fare.mean()[3][0][0][0])#7.923984210526318
    ## 选择中位数进行填充
    data_df['Fare'].fillna(data_df.groupby(['Pclass', 'Parch','SibSp','Embarked'])['Fare'].median()[3][0][0][0],inplace=True)
Cabin

Cabin缺失较多,如果没有很好的填充数据的方法时,建议将其直接删除。

复制代码
    data_df.drop('Cabin',inplace=True,axis=1)

数据缺失填充完成

继续分析数据
复制代码
    #从data_df得到训练集
    train_data = data_df[data_df.train==1]
    train_data['Survived'] = train_df['Survived']
    train_data.drop('train',axis=1,inplace=True)
    #从data_df得到测试训练集
    test_data = data_df[data_df.train==0]
    test_data.drop(['Survived','train'],axis=1,inplace=True)

特征相关程度分析

训练集
复制代码
    train_data.corr()
在这里插入图片描述
复制代码
    ### 从幸存和性别成负相关程度较大
    ### 从幸存和Pclass 成负相关程度较大
    ### 从幸存和Fare 成负相关程度较大
    train_data.corr()['Survived'].sort_values(ascending=False)
复制代码
    Survived    1.000000
    Fare        0.257307
    Parch       0.081629
    SibSp      -0.035322
    Age        -0.046230
    Embarked   -0.167675
    Pclass     -0.338481
    Sex        -0.543351

绘制特征相关程度热图

复制代码
    plt.figure( figsize=(10, 10))
    plt.title('Train Set Correlation HeatMap ',y=1,size=16)
    sns.heatmap(train_data.corr(),square = True,  vmax=0.7,annot=True,cmap='Accent')
在这里插入图片描述
存活情况
复制代码
    plt.bar(['Not Survived','Survived'],train_data['Survived'].value_counts().values)
    plt.title('Train_Set_Survived')
在这里插入图片描述

测试集

复制代码
    test_data.corr()
在这里插入图片描述
复制代码
    plt.figure( figsize=(10, 10))
    plt.title('Test Set Correlation HeatMap ',y=1,size=16)
    sns.heatmap(test_data.corr(),square = True,  vmax=0.7,annot=True,cmap='Accent')
在这里插入图片描述

连续性数据分布的情况

从Age、Fare的生存情况分布中可以看出的是

  • Age: 年龄较小者似乎具有较高的存活率;不同年龄段之间可能存在显著差异;后续研究可考虑将年龄划分为若干区间进行分析
  • Fare: 可以看出票价较高的乘客具有较高的存活率;这一发现提示票价可能在一定程度上影响乘客的存活机会
    Age与Fare在训练集与测试集中呈现相似的分布特征
复制代码
    continue_features = ['Age', 'Fare']
    survived = train_data['Survived'] == 1
    
    fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(20, 20))
    plt.subplots_adjust(right=1.5)
    
    for i, feature in enumerate(continue_features):    
        sns.distplot(train_data[~survived][feature], label='Not Survived', hist=True, color='#e74c3c', ax=axs[0][i])
        sns.distplot(train_data[survived][feature], label='Survived', hist=True, color='#2ecc71', ax=axs[0][i])
        
        sns.distplot(train_data[feature], label='Training Set', hist=False, color='#e74c3c', ax=axs[1][i])
        sns.distplot(test_data[feature], label='Test Set', hist=False, color='#2ecc71', ax=axs[1][i])
        
        axs[0][i].set_xlabel('')
        axs[1][i].set_xlabel('')
        
        for j in range(2):        
            axs[i][j].tick_params(axis='x', labelsize=20)
            axs[i][j].tick_params(axis='y', labelsize=20)
        
        axs[0][i].legend(loc='upper right', prop={'size': 20})
        axs[1][i].legend(loc='upper right', prop={'size': 20})
        axs[0][i].set_title('Distribution of Survival in {}'.format(feature), size=20, y=1.05)
    
    axs[1][0].set_title('Distribution of {} Feature'.format('Age'), size=20, y=1.05)
    axs[1][1].set_title('Distribution of {} Feature'.format('Fare'), size=20, y=1.05)
            
    plt.show()
在这里插入图片描述

类别特征分布情况

  • Embarked特征在取值为0的情况下显示出较高的存活率。
    • 性别特征中取值为0的样本具有较高的存活概率。
    • 乘客头等舱等级(Pclass)显示随等级降低而存活概率逐步下降。
    • 家庭成员数量相关的指标(SibSp与Parch)显示出相似的趋势, 因此建议将两者合并作为单一的家庭特征进行分析。
复制代码
    Categorical_features = ['Embarked', 'Parch','SibSp','Sex', 'Pclass']
    
    fig, axs = plt.subplots(ncols=2, nrows=3, figsize=(20, 20))
    plt.subplots_adjust(right=1.5, top=1.25)
    
    for i, feature in enumerate(Categorical_features, 1):    
        plt.subplot(2, 3, i)
        sns.countplot(x=feature, hue='Survived', data=train_data)
        
        plt.tick_params(axis='x', labelsize=20)
        plt.tick_params(axis='y', labelsize=20)
        
        plt.xlabel('{}'.format(feature), size=20, labelpad=15)
        plt.ylabel('Passenger Count', size=20, labelpad=15)    
        plt.legend(['Not Survived', 'Survived'], loc='upper center')
        plt.title('Count of Survival in {} Feature'.format(feature), size=20, y=1.05)
    plt.show()
    
    
    fig, axs = plt.subplots(ncols=2, nrows=3, figsize=(15, 15))
    plt.subplots_adjust(right=1.5, top=1.25)
    for i, feature in enumerate(Categorical_features, 1):    
        plt.subplot(2, 3, i)
        sns.pointplot(feature,y='Survived',data=train_data)
        
        plt.tick_params(axis='x', labelsize=20)
        plt.tick_params(axis='y', labelsize=20)
        
        plt.xlabel('{}'.format(feature), size=20, labelpad=15)
        plt.ylabel('Passenger Count', size=20, labelpad=15)    
        plt.title('Rate of Survival in {} Feature'.format(feature), size=20, y=1.05)
    plt.show()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

保存csv文件

复制代码
    train_data.to_csv('./train.csv',index=False)
    test_data.to_csv('./test.csv',index=False)
在这里插入图片描述

全部评论 (0)

还没有任何评论哟~