Kaggle泰坦尼克号之灾1--数据分析

作者: 七号萝卜 | 来源:发表于2017-03-26 20:09 被阅读2715次

    本文是参考寒小阳大神的博客:http://blog.csdn.net/han_xiaoyang/article/details/49797143
    中的实现所做的记录,想通过这个例子学习学习拿到数据后怎样进行分析,整个分析和分类的流程是什么样的。

    泰坦尼克号之灾主要是一个二分类问题。

    因为感觉光看不动手写一写只知道个原理,结果还是不知道怎么写。因此我又按照那篇博文撸了一遍代码。

    整个过程分两部分:第一步是先对原始数据进行分析;第二步才是进行学习建模。

    该篇记录先来进行第一部分,也就是数据分析的部分。拿到一组数据后,我们首先要做的是对这些数据进行初步的分析,看看哪些数据值得我们需要。

    当然首先要做的就是加载数据来看一看,这里用pandas库,一个非常好的数据分析库:

    # 首先引入需要用的库
    
    import pandas as pd # pandas专门用来进行数据分析,蛮有用的
    import numpy as np
    from pandas import Series,DataFrame
    
    # 加载数据,看看数据长什么样
    data_train = pd.read_csv('Train.csv')
    data_train.head()  # 打印头五个出来看看
    

    可以看到如下输出:

    泰坦尼克号数据表格

    有哪些属性都一目了然。可以看到有10多个字段(并不是所有字段都是特征属性哦):

    • PassengerId:乘客ID
    • Survived:是否获救
    • Pclass:乘客等级
    • Name:乘客姓名
    • Sex:性别
    • Age:年龄
    • SibSp:堂兄弟妹个数
    • Parch:父母与小孩个数
    • Ticket:船票信息
    • Fare:票价
    • Cabin:客舱
    • Embarked:登船港口

    接着看看这些数据的基本信息:

    data_train.info()
    

    打印如下:

    基本信息

    可以看到,RangeIndex是说总共有891个数据,列数有12列;并且能够看到每列数据的类型,而且能看出有些数据是不全的,比如Age只有714个数,Cabin只有204个数。

    再来看看详细点的描述呢:

    data_train.describe()
    

    输出:


    以上函数更能描述数据的一些事情。我们可以看到,上面的表格中将特征中数值型数据的一些属性计算了出来,可以一目了然的看到每类数值型特征的平均值,标准差,最小值等属性。比如Age一栏,看到乘客的平均年龄为29.6岁。

    接下来继续分析数据。看完了每个数据单独的关系,现在应该结合我们最终的目的来看看数据间相互的关系了。我们最终是分类,也就是想找出哪些特征与最终是否获救有关。因此我们可以看看每个或多个属性和最后获救Survived数据有什么样的关系。

    先来画画图吧:

    import matplotlib.pyplot as plt
    
    fig = plt.figure()
    fig.set(alpha=0.2) # 设定图表颜色alpha参数
    
    # 在一张大图里分列几个小图
    plt.subplot2grid((2,3),(0,0))
    data_train.Survived.value_counts().plot(kind='bar')
    plt.title(u"获救情况(1为获救)")
    plt.ylabel(u"人数")
    
    plt.subplot2grid((2,3),(0,1))
    data_train.Pclass.value_counts().plot(kind='bar')
    plt.ylabel(u"人数")
    plt.title(u"乘客等级分布")
    
    plt.subplot2grid((2,3),(0,2))
    plt.scatter(data_train.Survived,data_train.Age)
    plt.ylabel(u"年龄")
    plt.grid(b=True,which='major',axis='y')
    plt.title(u"按年龄看获救分布(1为获救)")
    
    plt.subplot2grid((2,3),(1,0),colspan=2)
    data_train.Age[data_train.Pclass == 1].plot(kind='kde')
    data_train.Age[data_train.Pclass == 2].plot(kind='kde')
    data_train.Age[data_train.Pclass == 3].plot(kind='kde')
    plt.xlabel(u"年龄")
    plt.ylabel(u"密度")
    plt.title(u"各等级的乘客年龄分布")
    plt.legend((u'头等舱',u'2等舱',u'3等舱'),loc='best')
    
    plt.subplot2grid((2,3),(1,2))
    data_train.Embarked.value_counts().plot(kind='bar')
    plt.title(u"各登船口岸人数")
    plt.ylabel(u"人数")
    
    plt.show()
    

    图如下:

    由上面的图我们又可以看到一些情况,比如获救情况不容乐观,300多人,连一半都没到;
    3等舱的人蛮多的;
    从年龄来看,遇难和获救的人跨度都很广;

    然后开始分析主要属性对获救的关系,先看看乘客等级:

    # 再来看看各乘客等级的获救情况
    fig = plt.figure()
    fig.set(alpha=0.2)
    
    Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()
    Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()
    df = pd.DataFrame({u'获救':Survived_1,u'未获救':Survived_0})
    df.plot(kind='bar',stacked=True)
    plt.title(u"各乘客等级的获救情况")
    plt.xlabel(u"乘客等级")
    plt.ylabel(u"人数")
    
    plt.show()
    

    图如下:

    乘客等级的获救情况

    可以看到在1等舱里面获救的几率就要大得多呢!果然有钱有权的就是好。

    接着看港口位置:

    fig = plt.figure()
    fig.set(alpha=0.2)
    
    Survived_E0 = data_train.Embarked[data_train.Survived == 0].value_counts()
    Survived_E1 = data_train.Embarked[data_train.Survived == 1].value_counts()
    df = pd.DataFrame({u"获救":Survived_E1,u"未获救":Survived_E0})
    df.plot(kind='bar',stacked=True)
    plt.title(u"各登陆港口乘客的获救情况")
    plt.xlabel(u"登陆港口")
    plt.ylabel(u"人数")
    
    plt.show()
    
    港口位置情况

    好像并没有什么有价值的。

    再来看性别:

    fig = plt.figure()
    fig.set(alpha=0.2)
    
    Survived_sex0 = data_train.Sex[data_train.Survived == 0].value_counts()
    Survived_sex1 = data_train.Sex[data_train.Survived == 1].value_counts()
    df = pd.DataFrame({u'获救':Survived_sex1,u'未获救':Survived_sex0})
    df.plot(kind='bar',stacked=True)
    plt.title(u"按性别看获救情况")
    plt.xlabel(u"性别")
    plt.ylabel(u"人数")
    plt.show()
    
    性别分布

    这幅图上明显可以看出,船上的人确实都蛮绅士的,贯彻落实副船长所说的“让小孩和女士先走”政策。

    再来细些,看看每个舱里的性别情况呢?

    fig=plt.figure()
    fig.set(alpha=0.65) # 设置图像透明度,无所谓
    plt.title(u"根据舱等级和性别的获救情况")
    
    ax1 = fig.add_subplot(141)
    data_train.Survived[data_train.Sex == 'female'][data_train.Pclass != 3].value_counts().plot(kind='bar',label='female highclass',color='#FA2479')
    ax1.set_xticklabels([u"获救",u"未获救"],rotation=0)
    ax1.legend([u"女性/高级舱"], loc='best')
    
    ax2=fig.add_subplot(142, sharey=ax1)
    data_train.Survived[data_train.Sex == 'female'][data_train.Pclass == 3].value_counts().plot(kind='bar', label='female, low class', color='pink')
    ax2.set_xticklabels([u"未获救", u"获救"], rotation=0)
    plt.legend([u"女性/低级舱"], loc='best')
    
    ax3=fig.add_subplot(143, sharey=ax1)
    data_train.Survived[data_train.Sex == 'male'][data_train.Pclass != 3].value_counts().plot(kind='bar', label='male, high class',color='lightblue')
    ax3.set_xticklabels([u"未获救", u"获救"], rotation=0)
    plt.legend([u"男性/高级舱"], loc='best')
    
    ax4=fig.add_subplot(144, sharey=ax1)
    data_train.Survived[data_train.Sex == 'male'][data_train.Pclass == 3].value_counts().plot(kind='bar', label='male low class', color='steelblue')
    ax4.set_xticklabels([u"未获救", u"获救"], rotation=0)
    plt.legend([u"男性/低级舱"], loc='best')
    
    plt.show()
    
    舱等级性别情况

    然后是堂兄妹等等:

    # 再看看其他的获救情况
    fig = plt.figure()
    fig.set(alpha=0.2)
    
    Survived_S0 = data_train.SibSp[data_train.Survived == 0].value_counts()
    Survived_S1 = data_train.SibSp[data_train.Survived == 1].value_counts()
    df = pd.DataFrame({u'获救':Survived_S1,u'未获救':Survived_S0})
    df.plot(kind='bar',stacked=True)
    plt.title(u"按堂兄妹看获救情况")
    plt.xlabel(u"堂兄妹个数")
    plt.ylabel(u"人数")
    plt.show()
    
    堂兄妹属性

    简化版(Parch属性):

    g = data_train.groupby(['Parch','Survived'])
    df = pd.DataFrame(g.count()['PassengerId'])
    df
    
    Parch属性和获救的关系

    好像并没啥关系吧。

    好吧,数据里还有一些比如船票应该是1人1张的,和最后是否获救应该没啥关系,因此暂时不用看了。

    还有就是有些数据不全的值,比如说Cabin,只有204个数据,这也是我们需要分析分析的,先来看看它的分布:

    data_train.Cabin.value_counts()
    
    打印出来的一部分。。。

    这Cabin数据也是。。一眼看上去感觉很多又乱,而且每个就那么几个。。一个一个看也太麻烦了。。就先看看Cabin这个数据有或没有两种情况和获救的关系吧。

    # Cabin值太分散了,很多都是只出现了1次,因此先看看这个值的有无,对于survival的分布状况
    fig = plt.figure()
    fig.set(alpha=0.2)
    
    Survived_cabin = data_train.Survived[pd.notnull(data_train.Cabin)].value_counts()
    Survived_nocabin = data_train.Survived[pd.isnull(data_train.Cabin)].value_counts()
    df = pd.DataFrame({u"登记了船舱":Survived_cabin,u"没登记船舱":Survived_nocabin}).transpose()
    df.plot(kind='bar',stacked=True)
    plt.title(u"按Cabin有无看获救情况")
    plt.xlabel(u"Cabin有无")
    plt.ylabel(u"人数")
    
    plt.show()
    
    登记有无船舱

    看样子好像有船舱记录的获救比例高些啊,那么就先这样把Cabin分成Yes和No吧,作为一个特征。

    接下来还有一个拥有缺失值的属性Age年龄,其实这个属性应该还是有些关键的,因为副船长说过嘛,小孩也是优先级高的,因此Age或许是个比较大的影响因子。但是作为候选特征的Age数据却不全,这怎么办呢?

    遇到缺值的情况,一般有几种常见的处理方式:

    1. 如果缺失值的样本占总数的比例极高,我们可能直接丢弃,因为它本来就没几个嘛,或许是噪点呢。
    2. 如果缺失值的样本适中,而且该属性不是连续值的特征(就像刚才的Cabin,可以看做类目属性),就可以把NaN作为一个新类别,加入到类别特征中去;(刚才是因为Cabin里类目太分散了,每个的数量又很稀少,因此就定了有和无两个类目)
    3. 如果缺失值的样本适中,而该属性又是连续型的,有时候就会考虑给定一个step(比如这里的age,我们可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个type加到属性类目中。
    4. 有些情况下,缺失的值个数并不是特别多,那我们也可以试着根据已有的值,拟合一下数据,补充上。

    在Age值的处理上,这里可以采用拟合补全的方法。(比如用机器学习里面的回归):

    from sklearn.ensemble import RandomForestRegressor
    
    # 使用RandomForestRegressor填补缺失的年龄属性
    def set_missing_ages(df):
        # 把已有的数值型特征取出丢进RandomForestRegressor中
        age_df = df[['Age','Fare','Parch','SibSp','Pclass']]
        
        known_age = age_df[age_df.Age.notnull()].as_matrix()
        unknown_age = age_df[age_df.Age.isnull()].as_matrix()
        
        y = known_age[:,0]
        
        X = known_age[:,1:]
        
        # fit到RandomForestRegressor中
        rfr = RandomForestRegressor(random_state=0,n_estimators=2000,n_jobs=-1)
        rfr.fit(X,y)
        
        # 用模型进行未知年龄结果预测
        predictedAges = rfr.predict(unknown_age[:,1::])
        
        # 用预测结果补全原缺失数据
        df.loc[(df.Age.isnull()),'Age'] = predictedAges
        
        return df,rfr
    
    def set_Cabin_type(df):
        df.loc[(df.Cabin.notnull()),'Cabin'] = 'Yes'
        df.loc[(df.Cabin.isnull()),'Cabin'] = 'No'
        return df
    
    data_train,rfr = set_missing_ages(data_train)
    data_train = set_Cabin_type(data_train)
    data_train
    
    打印部分数据

    训练出来了,现在没有缺失值了,看看:

    data_train.info()
    
    info

    可以看到已经没有缺失值了,当然那个Embarked少了两个,可以直接忽略。。

    那么特征分析的差不多了,要开始进行学习分类了。但还有一步需要做做。在这些特征中,有些特征是类目型特征并不是数值,而我们通常机器学习是需要用到的是数值型的特征,那么我们就该把对应的类目型特征转换为数值型特征。怎么做呢?

    一般来说可以因子化/one-hot编码。

    而且pandas里面有个get_dummies函数可以干这个事哦。

    # Cabin,原本是一个属性,取值为['Yes','No'],现在因子化后,就变成两个属性’Cabin_yes‘和’Cabin_No‘
    # 原本Cabin取值为yes的,在此处的'Cabin_yes'下取值为1,在'Cabin_no'下取值为0;反之亦然
    # 其它类目型同理
    
    dummies_Cabin = pd.get_dummies(data_train['Cabin'],prefix='Cabin')
    
    dummies_Embarked = pd.get_dummies(data_train['Embarked'],prefix='Embarked')
    
    dummies_Sex = pd.get_dummies(data_train['Sex'],prefix='Sex')
    
    dummies_Pclass = pd.get_dummies(data_train['Pclass'],prefix='Pclass')
    
    df = pd.concat([data_train,dummies_Cabin,dummies_Embarked,dummies_Sex,dummies_Pclass],axis=1)
    # 丢掉一些不需要的值了
    df.drop(['Pclass','Name','Sex','Ticket','Cabin','Embarked'],axis=1,inplace=True)
    df
    

    现在可以看到特征全是数值型的,并且都是我们需要的特征了。

    # 再次打印数据描述来看看
    df.describe()
    
    有较多,这里没展示完

    我们可以看到Age和Fare的范围跨度有点大啊,分别是0.4280,0512。这应该要处理一下了,不然会影响到收敛速度的,因此需要对这两个数进行所说的归一化。话说还有PassengerId呢,这属性一看就是个id,不是特征,就不管了。

    # 数据分析完,就开始对数据进行预处理了,比如归一化。
    import sklearn.preprocessing as preprocessing
    
    scaler = preprocessing.StandardScaler()
    
    age_scale_param = scaler.fit(df['Age'])
    
    df['Age_scaled'] = scaler.fit_transform(df['Age'],age_scale_param)
    
    fare_scale_param = scaler.fit(df['Fare'])
    
    df['Fare_scaled'] = scaler.fit_transform(df['Fare'],fare_scale_param)
    df
    

    数据预处理的处理完了,接下来就可以进行相应的建模了。一般就使用sklearn来进行建模了。

    泰坦尼克号的初步数据分析基本到这就完成了,下一篇就根据以上处理过的数据进行分类模型的建立以及后续的分析。

    相关文章

      网友评论

        本文标题:Kaggle泰坦尼克号之灾1--数据分析

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