美文网首页
kaggle项目:泰坦尼克号生存率分析

kaggle项目:泰坦尼克号生存率分析

作者: 余三书 | 来源:发表于2019-02-15 10:12 被阅读0次

    一、提出问题:

    1912年4月15日,号称“永不沉没”的泰坦尼克号巨轮,在首航期间,撞上冰山之后沉没。船上的2224名乘客和机组人员,只有772人存活了下来,生存率只有32%,让人唏嘘不已。

    导致大量的没法存活的重要原因之一,就是没有足够的救生艇,在上船前,露丝就曾向船长提出救生艇不够的问题。虽然幸存下来有一些运气因素,但是,有一些人可能比其他人更有可能生存,比如妇女,儿童以及上层阶级。

    所以,我们研究的问题是:什么样的人能够更容易在泰坦尼克号存活?


    二、理解数据:

    1.采集数据

    数据来源于kaggle平台项目:点击下载Kaggle泰坦尼克号数据

    2.导入数据

    import os  #查看工作路径,首先要导入os工作包。

    os.getcwd()  # 查看默认工作路径。

    os.chdir("/Users//Desktop/KAGGLE/datas/")  #修改工作路径为文件存放路径。

    导入处理数据包

    import numpy as np

    import pandas as pd

    导入数据

    训练数据集

    train = pd.read_csv("./train.csv")

    测试数据集

    test  = pd.read_csv("./test.csv")

    print ('训练数据集:',train.shape,'测试数据集:',test.shape)

    合并数据集,方便同时对两个数据集进行清洗

    full = train.append( test , ignore_index = True )

    3.查看数据

    查看数据

    full.head()

    查看每一列的数据类型,和数据总数

    full.info()

    根据上面打印的结果,我们发现数据总共有1309行。

    其中数据类型列:年龄(Age)、船舱号(Cabin)里面有缺失数据:

    年龄(Age)里面数据总数是1046条,缺失了1309-1046=263,缺失率263/1309=20%

    船票价格(Fare)里面数据总数是1308条,缺失了1条数据

    字符串列:

    登船港口(Embarked)里面数据总数是1307,只缺失了2条数据,缺失比较少

    船舱号(Cabin)里面数据总数是295,缺失了1309-295=1014,缺失率=1014/1309=77.5%,缺失比较大

        这为我们下一步数据清洗指明了方向,只有知道哪些数据缺失数据,我们才能有针对性的处理。


    三、数据清洗

    1.缺失值处理

    在前面,理解数据阶段,我们发现数据总共有1309行。

     其中数据类型列:年龄(Age)、船舱号(Cabin)里面有缺失数据。 

     字符串列:登船港口(Embarked)、船舱号(Cabin)里面有缺失数据。

    用均值填充年龄以及船票价格的缺失值:

     #年龄(Age)缺失率为20%:

    full['Age']=full['Age'].fillna( full['Age'].mean() )

     #船票价格(Fare)缺失1条数据:

    full['Fare'] = full['Fare'].fillna( full['Fare'].mean() )

    #登船港口缺失2条数据,用众数填充:

    full['Embarked'] = full['Embarked'].fillna( 'S’ )

    #船舱号缺失值为77.5%,用U填充:

    full['Cabin'] = full['Cabin'].fillna( 'U’ )


    四、特征提取

    1.数据分类:

      数值类型:

      乘客编号(PassengerId),年龄(Age),船票价格(Fare),同代直系亲属人数(SibSp),不同代直系亲属人数(Parch)

      时间序列:无

      分类数据:

      1)有直接类别的

      乘客性别(Sex):男性male,女性female

      登船港口(Embarked):出发地点S=英国南安普顿Southampton,途径地点1:C=法国 瑟堡市Cherbourg,出发地点2:Q=爱尔兰 昆士敦Queenstown

      客舱等级(Pclass):1=1等舱,2=2等舱,3=3等舱

      2)字符串类型:可能从这里面提取出特征来,也归到分类数据中

      乘客姓名(Name)

      客舱号(Cabin)

      船票编号(Ticket)

    2.分类数据处理:

    2.1 乘客性别(Sex)

    将性别的值映射为数值:

    男(male)对应数值1,女(female)对应数值0

    sex_mapDict={'male':1,

                'female':0}

    #map函数:对Series每个数据应用自定义的函数计算

    full['Sex']=full['Sex'].map(sex_mapDict)

    2.2 登船港口(Embarked)

    #存放提取后的特征

    embarkedDf = pd.DataFrame()

    使用get_dummies进行one-hot编码,产生虚拟变量(dummy variables),列名前缀是Embarked

    embarkedDf = pd.get_dummies( full['Embarked'] , prefix='Embarked' )

    embarkedDf.head()

    #添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full,并把登船港口(Embarked)删掉。

    full = pd.concat([full,embarkedDf],axis=1)

    full.drop('Embarked',axis=1,inplace=True)

    2.3 客舱等级(Pclass)

    客舱等级(Pclass):

    1=1等舱,2=2等舱,3=3等舱

    #存放提取后的特征

    pclassDf = pd.DataFrame()

    #使用get_dummies进行one-hot编码,列名前缀是Pclass

    pclassDf = pd.get_dummies( full['Pclass'] , prefix='Pclass’ )

    #删掉客舱等级(Pclass)这一列

    full.drop('Pclass',axis=1,inplace=True)

    字符串类型:

    2.4  乘客姓名(Name)

    定义函数:从姓名中获取头衔:

    def getTitle(name):

        str1=name.split( ',' )[1] #Mr. Owen Harris

        str2=str1.split( '.' )[0]#Mr

        #strip() 方法用于移除字符串头尾指定的字符(默认为空格)

        str3=str2.strip()

        return str3

    #存放提取后的特征

    titleDf = pd.DataFrame()

    #map函数:对Series每个数据应用自定义的函数计算

    titleDf['Title'] = full['Name'].map(getTitle)

    titleDf.head()

    定义以下几种头衔类别:

    Officer政府官员

    Royalty王室(皇室)

    Mr已婚男士

    Mrs已婚妇女

    Miss年轻未婚女子

    Master有技能的人/教师

    #姓名中头衔字符串与定义头衔类别的映射关系

    title_mapDict = {

                        "Capt":       "Officer"; "Col":  "Officer"; 

                       "Major": "Officer";     "Jonkheer":   "Royalty",

                        "Don": "Royalty";     "Sir" :       "Royalty",

                        "Dr": "Officer";    "Rev": "Officer",

                        "the Countess":"Royalty",

                        "Dona": "Royalty",;    "Mme": "Mrs",

                       "Mlle": "Miss";     "Ms":"Mrs",

                        "Mr" :  "Mr";    "Mrs" : "Mrs",

                        "Miss" :"Miss";    "Master" : "Master",

                        "Lady" : "Royalty"}

    #map函数:对Series每个数据应用自定义的函数计算

    titleDf['Title'] = titleDf['Title'].map(title_mapDict)

    #使用get_dummies进行one-hot编码

    titleDf = pd.get_dummies(titleDf['Title'])

    titleDf.head()

    #添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full

    full = pd.concat([full,titleDf],axis=1)

    #删掉姓名这一列

    full.drop('Name',axis=1,inplace=True)

    2.5  客舱号(Cabin)

    #存放客舱号信息

    cabinDf = pd.DataFrame()

    客场号的类别值是首字母,例如:

    C85 类别映射为首字母C

    full[ 'Cabin' ] = full[ 'Cabin' ].map( lambda c : c[0] )

    ##使用get_dummies进行one-hot编码,列名前缀是Cabin

    cabinDf = pd.get_dummies( full['Cabin'] , prefix = 'Cabin’ )

    #添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full

    full = pd.concat([full,cabinDf],axis=1)

    #删掉客舱号这一列

    full.drop('Cabin',axis=1,inplace=True)

    2.6    家庭人数

    #存放家庭信息

    familyDf = pd.DataFrame()

    家庭人数=同代直系亲属数(Parch)+不同代直系亲属数(SibSp)+乘客自己

    (因为乘客自己也是家庭成员的一个,所以这里加1)

    familyDf[ 'FamilySize' ] = full[ 'Parch' ] + full[ 'SibSp' ] + 1

    家庭类别:

    小家庭Family_Single:家庭人数=1

    中等家庭Family_Small: 2<=家庭人数<=4

    大家庭Family_Large: 家庭人数>=5

    #if 条件为真的时候返回if前面内容,否则返回0

    familyDf[ 'Family_Single' ] = familyDf[ 'FamilySize' ].map( lambda s : 1 if s == 1 else 0 )

    familyDf[ 'Family_Small' ]  = familyDf[ 'FamilySize' ].map( lambda s : 1 if 2 <= s <= 4 else 0 )

    familyDf[ 'Family_Large' ]  = familyDf[ 'FamilySize' ].map( lambda s : 1 if 5 <= s else 0 )

    familyDf.head()

    #添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full

    full = pd.concat([full,familyDf],axis=1)

    full.head()


    五、特征选择

    相关系数法:计算各个特征的相关系数

    #相关性矩阵

    corrDf = full.corr()

    corrDf

    查看各个特征与生成情况(Survived)的相关系数,

    ascending=False表示按降序排列

    corrDf['Survived'].sort_values(ascending =False)

    我们发现头衔Mrs和生存情况有着很强的正线性相关,头衔Mr和生存情况有负线性相关性。有可能当时船上执行了,发生灾难时:妇女儿童优先。虽然灾难发生,很多人还是很好的遵守了这一人性的原则。

    根据各个特征与生成情况(Survived)的相关系数大小,我们选择了这几个特征作为模型的输入:

    头衔(前面所在的数据集titleDf)、客舱等级(pclassDf)、家庭大小(familyDf)、船票价格(Fare)、船舱号(cabinDf)、登船港口(embarkedDf)、性别(Sex)

    #特征选择

    full_X = pd.concat( [titleDf,#头衔

                         pclassDf,#客舱等级

                         familyDf,#家庭大小

                         full['Fare'],#船票价格

                         cabinDf,#船舱号

                         embarkedDf,#登船港口

                         full['Sex']#性别

                        ] , axis=1 )

    full_X.head()


    六、模型构建

    1.建立训练数据集和测试数据集

    用训练数据和某个机器学习算法得到机器学习模型,用测试数据评估模型

    #原始数据集:特征

    source_X = full_X.loc[0:sourceRow-1,:]

    #原始数据集:标签

    source_y = full.loc[0:sourceRow-1,'Survived']   

    #预测数据集:特征

    pred_X = full_X.loc[sourceRow:,:]

    source_y

    source_X

    pred_X

    from sklearn.model_selection import train_test_split

    #建立模型用的训练数据集和测试数据集

    train_X, test_X, train_y, test_y = train_test_split(source_X ,

                                                        source_y,

                                                        train_size=.80)

    #交叉验证

    #cross_validation.cross_val_score(LR, train_X , train_y, cv=10)

    #输出数据集大小

    print ('原始数据集特征:',source_X.shape,

           '训练数据集特征:',train_X.shape ,

          '测试数据集特征:',test_X.shape)

    print ('原始数据集标签:',source_y.shape,

           '训练数据集标签:',train_y.shape ,

          '测试数据集标签:',test_y.shape)

    2.模型训练评估

    逻辑回归:

    #第1步:导入算法

    from sklearn.linear_model import LogisticRegression

    #第2步:创建模型:逻辑回归(logisic regression)

    model = LogisticRegression()

    #第3步:训练模型

    model.fit( train_X , train_y )

    # 分类问题,score得到的是模型的准确率

    model.score(test_X , test_y )

    结果:0.83240223463687146

    神经网络:

    from sklearn.neural_network import MLPClassifier

    mlp = MLPClassifier(hidden_layer_sizes=(30,20,20,20), max_iter=1000)

    # 计算交叉验证的准确率

    mlp.fit(train_X,train_y)

    mlp.score(test_X , test_y)

    结果:0.83798882681564246

    KNN:

    from sklearn import neighbors

    knn = neighbors.KNeighborsClassifier(n_neighbors=8)

    scores = cross_validation.cross_val_score(knn, train_X , train_y, cv=5)

    print(scores.mean())

    结果:0.762612035851

    决策树:

    from sklearn import tree

    dtree = tree.DecisionTreeClassifier(max_depth=3, min_samples_split=4)

    scores = cross_validation.cross_val_score(dtree, train_X , train_y, cv=3)

    print(scores.mean())

    结果:0.815921283768

    随机森林:

    from sklearn.ensemble import RandomForestClassifier

    RF = RandomForestClassifier(n_estimators=100, min_samples_split=4)

    scores = cross_validation.cross_val_score(RF, train_X , train_y, cv=3)

    print(scores.mean())

    结果:0.81598062954

    Bagging:

    from sklearn.ensemble import BaggingClassifier

    bagging_clf = BaggingClassifier(RF,n_estimators=20)

    scores = cross_validation.cross_val_score(bagging_clf,train_X , train_y, cv=3)

    print(scores.mean())

    结果:0.831410530314

    Adaboost:

    from sklearn.ensemble import AdaBoostClassifier

    adaboost = AdaBoostClassifier(bagging_clf, n_estimators=10)

    scores = cross_validation.cross_val_score(adaboost, train_X , train_y, cv=3)

    print(scores.mean())

    结果:0.827196980487

    Stacking:

    from sklearn.ensemble import VotingClassifier

    sclf = VotingClassifier([('LR',LR),('mlp',mlp),('bagging_clf',bagging_clf),('knn',knn),('dtree',dtree)])

    scores = cross_validation.cross_val_score(sclf, train_X , train_y, cv=15)

    print(scores.mean())

    结果:0.829916895836

    结果可以看出:神经网络预测结果最好。


    七、方案实施

    1.结果上传

    使用预测数据集到底预测结果,并保存到csv文件中,上传到Kaggle中,就可以看到排名。

    #使用机器学习模型,对预测数据集中的生存情况进行预测

    pred_Y = model.predict(pred_X)

    '''

    生成的预测值是浮点数(0.0,1,0)

    但是Kaggle要求提交的结果是整型(0,1)

    所以要对数据类型进行转换

    '''

    pred_Y=pred_Y.astype(int)

    #乘客id

    passenger_id = full.loc[sourceRow:,'PassengerId']

    #数据框:乘客id,预测生存情况的值

    predDf = pd.DataFrame(

        { 'PassengerId': passenger_id ,

         'Survived': pred_Y } )

    predDf.shape

    predDf.head()

    #保存结果

    predDf.to_csv( 'titanic_pred.csv' , index = False )

    2.结论

    2.1   从性别来看:女性比男性(负线性相关)更容易存活,可能是在灾难来临的时候,整个群体遵循了“女人小孩先走的”的人性原则。

    2.2  从仓位来看:高等级的仓位,生存率更高,可能是因为高等级的仓位处于上层甲板,逃生比低级仓位更容易

    2.3  从头衔可以看出社会等级的差异,不同的社会等级往往生存率也有所不同。

    相关文章

      网友评论

          本文标题:kaggle项目:泰坦尼克号生存率分析

          本文链接:https://www.haomeiwen.com/subject/qdxpeqtx.html