Titanic罹难乘客预测(上篇)

Titanic罹难乘客预测

1.1背景介绍

“泰坦尼克号罹难乘客”的预测任务在Kaggle平台发布[点这里],https://www.kaggle.com/)这个预测问题一直以来都做为初学者的练习项目。关于罹难者由于救生艇的数量有限,所以要考虑优先营救哪些人。那么可能影响到我们的是性别和年龄吗?还是有更多信息等我们去挖掘呢。废话不多说,我们来看下这项预测任务有哪些数据ps:官网下载数据,这些数据可以给我们提供哪些信息呢!

1.2数据分析与处理

将数据下载完成保存至指定的盘符,这里利用Jupyter notebook对数据进行读取与处理和分析,在这里我们分析数据时要借助可视化以便更加明晰数据之间的关系。

大致看数据 :

 ![数据](//img-blog.csdn.net/20180315160813317?watermark/2/text/Ly9ibG9nLmNzZG4ubmV0L3NrbGRlY3Nkbg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

下拉至末尾可以看到:891 rows × 12 columns(891名乘客)又或者:
只观察前5行数据
此时大致对于数据有一个初步的认识,接下来再去分析这些行行列列的是些什么数据,提供了什么信息,对于我们特征的选择有什么帮助,是否有缺失值等等。

探查数据 :

    PassengerId:乘客ID
    Survived   :是否获救(取值为0和1)
    Pclass     :乘客等级(船舱不同分为1、2、3等)
    Name       :乘客姓名
    Sex        :性别 (male    、female)
    Age        :年龄
    SibSp      :(堂)兄弟或(堂)姐妹个数
    Parch      :父母与小孩的个数
    Ticket     :船票信息
    Fare       :票价
    Cabin      :客舱
    Embarked   :登船港口

数据分析 :

首先检查,我们拿到的数据是否完整,是否含有缺失值,这些缺失值应该怎样处理,是否影响我们特征的选择,以下将展开分析。
查看缺失情况与数据类型其中,我们可以观察到:Age 714 non-null float64,Cabin 204 non-null object,Embarked 889 non-null object,这三行信息可以看出,Age和Cabin,Embarked是存在缺失值的,而对于缺失值的处理,我们要进一步分析是否用于特征的选取。
然而,想要更一步的了解数据数值情况,我们可以用下面的方法进行查看:
如此便获得了更多的数值信息,比如:count为总计个数,std标准差(),mean(平均数)字段告诉我们,大概0.383838的人最后获救了,2或3等舱的人数比1等舱要多,平均乘客年龄大概是29.7岁(计算过程不含缺失值的)等等。
此时,我们已经看到每位乘客有很多属性(特征),可能还存在缺失值,那么这些信息都和我们最后要预测的获救率有关系吗?这时我们是否可以将这些属性与Survived进行一些关联的对比?此时就用到了可视化的操作,将数据进行可视化是数据分析的一个很好的工具。之前学了部分可视化的东东,正好拿着这个例子练习一下。

@skl--python
plt.rcParams["font.sans-serif"] = ["SimHei"]
fig = plt.figure(figsize = (10,8) , dpi = 80)
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)

df_Survived = df["Survived"].value_counts()
labels = ["未获救","获救"]
colors = ["#7199cf","#ffff10"]
ax1.pie(df_Survived.values , labels = labels , colors = colors, startangle = 90 , autopct = "%.f%%" , pctdistance = 0.4)

x = np.unique(df["Pclass"])
y = df.groupby("Pclass")["Survived"].sum()
ax2.bar(np.arange(len(x)),y,width = 0.4,color = "#FA2479",tick_label = x)
ax2.set_xlabel("Pclass")
ax2.set_ylabel("获救人数")
ax2.set_title("乘客等级与获救人数")
ax2.set_ylim(0,160)
#for a,b in zip(np.arange(len(x)),y):
#   ax.text(a,b+3,b,ha = "center",fontsize = 10)
plt.show() 

这里写图片描述
通过上面的两幅图,可以清楚的看出获救人数占了总人数的38%,未获救人数占了62%。还有乘客等级与获救人数的关系,从上面的图中可以看出,乘客的等级对于获救情况还是有影响的,毕竟一等舱的获救人数更多一些哦!也就是说数据集中的Pclass这一列要做为预备的特征参与模型的训练。这只是简单的初步分析后面会对其他特征比较细化的进行分析。
既然已经观察了不同等级的舱位确实影响获救情况,那么不妨再往深了看下不同等级舱位中性别是否也有影响呢?

@skl--python
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams['axes.unicode_minus'] = False
df_grouped1 = df.groupby(["Sex","Pclass"])["Survived"].sum()
female = df_grouped1.loc["female"]
male  = df_grouped1.loc["male"]
labels = df_grouped1.loc["male"].index
fig,ax = plt.subplots(figsize = (8,5) , dpi = 80)
ax.barh(np.arange(len(female)),female,label = "female",height = 0.5)
ax.barh(np.arange(len(male)),-male,label = "male",height = 0.5,tick_label = labels)
ax.set(xlabel = "获救人数",ylabel = "等级舱",title = "不同等级舱位,男女获救人数")
ax.set_xlim(-100,100)
ax.legend()
for a,b in zip(female,np.arange(len(female))):
    ax.text(a+4,b,a,ha = "center",fontsize = 10)
for a,b in zip(male,np.arange(len(male))):
    ax.text(-a-4,b,a,ha = "center",fontsize = 10)
plt.show()

这里写图片描述
通过上图可以很明确的看出女性真的是比男性获救的人数更多。那么性别也确实影响着获救情况,也把Sex这列纳入预备特征中。此外,我认为年龄也是影响获救情况的一个因素啊,验证一下:

@skl--python
#按年龄看获救情况的箱线图,因为箱线图需要在完整的数据集上做既没有缺失值,所以暂时先用我处理好的数据集(后面会进行数据处理的步骤)。
plt.rcParams["font.sans-serif"] = ["SimHei"]
data_train2_Survived = data_train2.sort_values("Survived")
age = []
Survived_level = data_train2["Survived"].unique()
for i in Survived_level :
    age.append(data_train2_Survived.loc[data_train2_Survived["Survived"] == i,"Age"])
fig,ax = plt.subplots(figsize = (8,5),dpi = 80)
ax.boxplot(age,labels = Survived_level,showmeans = True)
ax.tick_params(top = "off")
ax.grid(True)
ax.set_ylabel("年龄")
ax.set_title("按年龄看获救情况(1:获救)")
plt.show()

这里写图片描述

##将多个图合并到一张图中有利于观察和对比
df.Age[df.Pclass == 1].plot(kind='kde')   
df.Age[df.Pclass == 2].plot(kind='kde')
df.Age[df.Pclass == 3].plot(kind='kde')
plt.xlabel("年龄",fontsize = 15)# plots an axis lable
plt.ylabel("密度",fontsize = 15) 
plt.title("各等级乘客的年龄分布",fontsize = 15)
plt.legend(("头等舱", "2等舱","3等舱"),loc="best") # sets our legend for our graph.
plt.grid(True)
plt.show()

这里写图片描述
年龄的分布密度曲线图对我们分析也是有帮助的,我们可以看出哪一阶段的年龄密度情况。箱线图中盒子中间的小三角形表示均值(showmeans = True)我们可以看到获救的人数中年龄的均值在29岁左右。盒子上面的那条线表示75%的位置的数:37岁左右,盒子下面的那条线表示下四分位(25%)位置的数字即20岁。大致上我们可以得到这些信息。可以看出年龄也是对获救情况有影响的哦!同样加入预备特征中。现在为止剩下的属性中有: PassengerId,Survived,Name,SibSp,Parch,Ticket,Fare,Cabin,Embarked。这些属性中Survived是作为模型的label的所以不会成为我们的预备特征,PassengerId这个是乘客的ID是唯一的值对于获救貌似也没有神魔影响可以排除,而Ticket即船票的信息可能会是记录一些在哪里上船要去哪里之类的可能也是没有影响的。重点放在其它属性中,以下便是对其它属性的窥探。
Embarked:登船港口也许和出身地位有关系呢,比如某个登船港口附近是豪宅聚集地呢。如下:

@skl--python
plt.rcParams["font.sans-serif"] = ["SimHei"]
fig = plt.figure(figsize = (10,8) , dpi = 80)
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(222)

x = df["Embarked"].unique()
y = df["Embarked"].value_counts()
ax1.bar(np.arange(len(x)),y,width = 0.4,color = "c",tick_label = x)
ax1.set_xlabel("Embarked")
ax1.set_ylabel("人数")
ax1.set_title("各登船口岸上船人数")
#
y = df.groupby("Embarked")["Survived"].sum().round(1).sort_values(ascending = False)
ax2.bar(np.arange(len(x)),y,width = 0.4,color = "lightcoral",tick_label = x)
ax2.set_xlabel("Embarked")
ax2.set_ylabel("获救人数")
ax2.set_title("各登船口岸获救人数")
plt.ylim(0,600)
plt.show()

这里写图片描述
是吧,S港口获救人数还是比其它两个登船港口获救要高很多的。所以Embarked是要做为预备特征的哦!
Cabin乘客的客舱,这个还是很有必要看下的吧,毕竟有分不同客舱当然肯定是等级也有不同喽,但是此列有很多缺失值我们按照有无Cabin记录来看下获救情况。

@skl--python
plt.rcParams["font.sans-serif"] = ["SimHei"]
x1 = df.Survived[pd.notnull(df.Cabin)].value_counts()  #有记录:1:136,0:68
x2 = df.Survived[pd.isnull(df.Cabin)].value_counts().round(1).sort_values()  #无记录:1:206,0:481
df1 = pd.DataFrame({"有":x1, "无":x2}).transpose()
m = df1[0].values
n = df1[1].values
labels = pd.DataFrame({"有记录":x1,"无记录":x2}).transpose().index
fig,ax = plt.subplots(figsize = (6,5) , dpi = 80)
ax.bar(np.arange(len(m)),m,width = 0.3,color ="g",tick_label = labels,label = "绿色:未获救")
ax.bar(np.arange(len(n)),n,width = 0.3,bottom = m,color = "pink",label = "粉色:获救")
ax.set_xlabel("Cabin")
ax.set_ylabel("人数")
ax.set_title("按Cabin有无记录看获救情况")
ax.legend(loc = "best")
plt.show()

这里写图片描述
如果按比例来看的话,很清楚的看到Cabin有记录时获救概率更高哦!所以此时将Cabin也纳入预备特征中。
下面再来看下还有两列属性常规来说,应该是有影响的。就是SibSp:(堂)兄弟或(堂)姐妹个数和Parch:父母与小孩的个数。因为PassengerId值是唯一的,每个乘客都有一个ID,我们就利用以”SibSp(Parch)”,”Survived”进行分组然后统计PassengerId的个数大致如下:

这里写图片描述

这里写图片描述
可以看到还是对获救情况有影响的,所以将这两列纳入预备特征中。
好了,目前为止我们的预备特征有:Pclass,Sex,Age,SibSp,Parch,Cabin,Embarked,Fare(票价)。这些是我们的初步分析(借助可视化)。


数据处理

借助了可视化操作,对数据进行了分析,找到了哪些特征需要加入我们后续的建模中。现在回过头再看,我们还需要一个特别重要的步骤。因为最开始的时候我们对于数据的探查,发现数据并不是完整的,那么就需要我们对数据进行处理成为完整的数据。
再次看数据:

这里写图片描述

这里写图片描述
可以看到有三个属性是存在缺失值的,重要的是这三个属性:Age,Cabin,Embarked是作为我们的预备特征的,所以必须要进行处理,好吧一个一个来从易到难。先看Embarked这列:有889个非空值,存在2个缺失值,这里我们采用向前填充的方法。因为确实值的数量很少,所以采用填充的方法对结果影响不是很大,你也可以采用其他方法填充。

这里写图片描述
之后我们对Cabin,Embarked一起进行处理:首先来说Cabin,我们在做数据分析时因为这一列确实存在了很多缺失值,只有204个数据是非空的并且这些非空值应该还是唯一值。所以我们就按照有无Cabin记录来对它进行处理,有记录为“Yes”,无记录为“No”。只剩下Age列了,我们这里用scikit-learn中的RandomForest来拟合一下缺失的年龄数据(注:RandomForest是一个用在原始数据中做不同采样,建立多棵DecisionTree,再进行average等等来降低过拟合现象,提高结果的机器学习算法)

@skl--python
from sklearn.ensemble import RandomForestRegressor
# 使用 RandomForestClassifier 填补缺失的年龄属性

def set_missing_ages(df):
   # 把已有的数值型特征取出来丢进Random Forest Regressor中
    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即目标年龄
    y = known_age[:,0]                                                 #known_age中的第一列也就是Age列的所有非空值的数据
    # X即特征属性值
    x = known_age[:,1:]                                                #known_age中从第二列开始(除了Age列)到最后的值(原始数据这四列          就不含缺失值)

    # fit到RandomForestRegressor之中
    rfr = RandomForestRegressor(random_state = 0,n_estimators =        2000,n_jobs = -1)  #
    rfr.fit(x,y)
    # 用得到的模型进行未知年龄结果预测
    predictedAges = rfr.predict(unknown_age[:,1:])                     #unknown_age[:,1:]为:Age这列是缺失值时,其他四列的值
    # 用得到的预测结果填补原缺失数据
    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
#if __name__ =="__main__":
data_train,rfr = set_missing_ages(df)
data_train = set_Cabin_type(df)
data_train

这里写图片描述

这里写图片描述
现在为止已经完成了对数据的大致处理,想一想后续我们要用逻辑回归建模,则需要我们输入的特征都是数值型特征。所以我们会先对类目型的特征因子化。例如:
以Cabin为例,通过上面的数据处理后,其取值是[“Yes”,“No”],现在将其展开为:“Cabin_Yes”,“Cabin_No”两个属性。

•原本Cabin取值为yes的,在此处的”Cabin_yes”下取值为1,在”Cabin_no”下取值为0
•原本Cabin取值为no的,在此处的”Cabin_yes”下取值为0,在”Cabin_no”下取值为1

这里使用pandas的”get_dummies”方法,并将其拼接在原来的”data_train”之上。

@skl--python
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")

data_train1 = pd.concat([data_train,dummies_Cabin,dummies_Embarked,dummies_Sex,dummies_Pclass],axis = 1)
data_train1.drop(["Pclass","Name","Sex","Ticket","Cabin","Embarked"],axis = 1,inplace = True)
data_train1

这里写图片描述
现在我们所需要的特征都是数值型的了,但是我们会发现Age和Fare两列数值的变化幅度还是很大的。逻辑回归与梯度下降算法中我们知道,各属性值之间scale差距太大,将对收敛速度造成影响,甚至不收敛。所以我们先用scikit-learn里面的preprocessing模块对它们做一个scaling,其实就是将一些变化幅度较大的特征化到[-1,1]之内。

@skl--python
#数据的标准化处理,scaling,其实就是将一些变化幅度较大的特征化到[-1,1]之内
import sklearn.preprocessing as preprocessing
scaler = preprocessing.StandardScaler()
age_scale_param = scaler.fit(data_train1["Age"].reshape(-1,1))

data_train1["Age_scaled"]=scaler.fit_transform(data_train1["Age"].reshape(-1,1),age_scale_param)

fare_scale_param = scaler.fit(data_train1["Fare"].reshape(-1,1))
data_train1["Fare_scaled"] = scaler.fit_transform(data_train1["Fare"].reshape(-1,1),fare_scale_param)
data_train1

这里写图片描述
目前为止,我们所需要的特征属性已经准备完毕,接下来初步建立模型。

建立模型

这里使用scikit-learn中的LogisticRegression进行建模。

@skl--python
from sklearn import linear_model

#用正则取出我们要的属性值
train_df = data_train1.filter(regex = "Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*")
train_np = train_df.as_matrix()
# y即Survival结果
y = train_np[:, 0]
# X即特征属性值
X = train_np[:, 1:]

# fit到LogisticRegression之中
Ln = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
Ln.fit(X, y)
Ln

这里写图片描述
以上是我们用之前准备的特征得到的模型。之后我们就要考虑将测试集用于此模型,提交看得到的效果如何了。同样的我们拿到test.csv数据集之后,进行与训练集同样的操作,数据处理,好吧,那么我们首先看下数据的大致信息是怎样的?

这里写图片描述

这里写图片描述
通过观察我们发现,Fare缺失值只有一个,那么我们就先对它进行填充:
如下(也可以用均值填充的哦)

这里写图片描述
那么,接下来需要处理的就是Age和Cabin了。
如下:

@skl--python
#test数据集中,只剩下Age列和Cabin列有缺失值了,同样用RandomForstRegressor模型(rfr仍为训练集中的模型)填上缺失的年龄
age_df1 = data_test[["Age","Fare","Parch","SibSp","Pclass"]]
null_age = age_df1[age_df1.Age.isnull()].as_matrix()               #在age_df1中挑出age列为空的age_df1。有五列值第一列age列全为空

predictedAges = rfr.predict(null_age[:,1:]) #拿着非空的数值列去做预测
data_test.loc[(data_test.Age.isnull()),"Age"] = predictedAges

data_test = set_Cabin_type(data_test)

dummies_Cabin = pd.get_dummies(data_test["Cabin"],prefix = "Cabin")
dummies_Embarked = pd.get_dummies(data_test["Embarked"],                                             prefix = "Embarked")
dummies_Sex = pd.get_dummies(data_test["Sex"],prefix = "Sex")
dummies_Pclass = pd.get_dummies(data_test["Pclass"],                                                prefix = "Pclass")

data_test = pd.concat([data_test,dummies_Cabin,dummies_Embarked,
                     dummies_Sex,dummies_Pclass],axis = 1)
data_test.drop(["Pclass","Name","Sex","Ticket","Cabin","Embarked"],              axis = 1,inplace = True)
data_test

这里写图片描述

这里写图片描述
以上全部完毕,我们可以拿着测试集到模型中检验一下啦!

@skl--python
test = data_test.filter(regex = "Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*")
predictions = clf.predict(test)
result = pd.DataFrame({"PassengerId":data_test["PassengerId"].as_matrix(),"Survived":predictions.astype(np.int32)})
result.to_csv("test_result.csv")

将结果导出,就可以去官网提交查看效果了。以上只是简单的一个流程,后续有时间还会继续进行更新。。。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值