罹难
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名乘客)又或者:
此时大致对于数据有一个初步的认识,接下来再去分析这些行行列列的是些什么数据,提供了什么信息,对于我们特征的选择有什么帮助,是否有缺失值等等。
探查数据 :
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")
将结果导出,就可以去官网提交查看效果了。以上只是简单的一个流程,后续有时间还会继续进行更新。。。
相关阅读
DNF10周年活动时间预测 DNF国服10周年活动什么时候开
dnf国服10周年活动什么时候开始?dnf即将迎来dnf国服十周年,一般活动都会在提前发喔,接下来一起来了解下dnf十周年活动预测吧!dnf国
在大变革来临之际,如果你的方向是错的,不顺应时代的潮流,不做出应对之策,在任何行业都没办法生存。即便是再庞大的商业帝国,也不能幸
月份 投标人数 额度 中标率 最低成交价 成交均价 成交时间 1月 168614 12832 7.6%
从小有过司机梦想的我,费了九牛二虎之力,终于成为人民优步和滴滴专车的兼职司机,体验到了满大街服务人民的乐趣。但作为一名曾经的媒
马尔可夫预测的性质及运用 对事件的全面预测,不仅要能够指出事件发生的各种可能结果,而且还必须给出每一种结果出现的概率,说明被预