泰坦尼克号生存预测python_泰坦尼克号生存预测(python)

1 探索性分析

对数据进行一个整体的理解

1.1 查看数据都有一些什么特征

将测试集和训练集合并,方便后续的数据处理

importpandas as pdimportseaborn as snsimportnumpy as npimportmatplotlib.pyplot as plt%matplotlib inline

train= pd.read_csv('G:\\titanic\\train.csv')

test= pd.read_csv('G:\\titanic\\test.csv')

testId= test["PassengerId"]

dataset= pd.concat(objs = [train,test],axis = 0).reset_index(drop=True)

train_len= len(train)

1349782-20180903095556142-1555449318.png

PassengerId => 乘客ID

Pclass => 乘客等级(1/2/3等舱位)

Name => 乘客姓名

Sex => 性别

Age => 年龄

SibSp => 堂兄弟/妹个数

Parch => 父母与小孩个数

Ticket => 船票信息

Fare => 票价

Cabin => 客舱

Embarked => 登船港口

查看数据集的信息,可以看到age、cabin、enkarked、fare都是存在缺失值的

dataset.info()

1349782-20180903095756081-1684498561.png

1.2 各特征与survived之间的关系

1.2.1 Age

采用训练集数据进行观察分析,可以看到最后存活下来的年龄会整体偏低一些,但是特征不够明显

sns.boxplot(y=train["Age"],x=train["Survived"])

1349782-20180903101612714-1621291684.png

1.2.2 Sex

lady first

获救人数里女性占比更大

fig =plt.figure()

fig.set(alpha=0.2) #设定图表颜色alpha参数

Survived_m= train.Survived[train.Sex == 'male'].value_counts()

Survived_f= train.Survived[train.Sex == 'female'].value_counts()

df=pd.DataFrame({'male':Survived_m, 'female':Survived_f})

df.plot(kind='bar', stacked=True)

plt.xlabel("survived")

plt.ylabel("number")

1349782-20180903102640045-1832252207.png

1.2.3 Pclass

船舱等级为1的获救几率更大

sns.barplot(x=train["Pclass"],y=train["Survived"])

1349782-20180903110144260-1805572366.png

1.2.4 SibSp/Parch

灾难来临家庭人数多的获救几率高还是低?

将兄弟姐妹和父母合并得到家庭总人数

可以看到家庭人数在2-4人之间获救可能性更高些,单身一人缺少帮助,家庭人数多的需要照顾更多家人

train["Fsize"] = train["SibSp"] + train["Parch"] + 1sns.barplot(x= train["Fsize"],y = train["Survived"])

1349782-20180903111005284-27892745.png

1.2.5 Fare

票价高的获救几率比较大,但是不明显。

同时可以看到Fare中存在一个异常值,需要将其剔除

sns.boxplot(y=train["Fare"],x=train["Survived"])

train["Fare"]=train["Fare"].replace(train["Fare"].max(),train["Fare"].median())

1349782-20180903111707204-1780220205.png

1349782-20180903112339733-146809786.png

1.2.6 Name

乘客名字中带有相应的称呼,称呼可能代表这他的社会地位

其中Mr Miss Mrs Master 所占数量最多,其他比较少的都统一替换为rare

name_list = [i.split(",")[1].split(".")[0].strip() for i in dataset["Name"]]#按指定字符将字符串切片为列表

dataset["Title"] =pd.DataFrame(name_list)#g = sns.countplot(dataset["Title"])#g = plt.setp(g.get_xticklabels(),rotation=45)

dataset["Title"] = dataset["Title"].replace(['Lady', 'the Countess','Countess','Capt','Col','Don', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'],"rare")#dataset["Title"] = dataset["Title"].map({"rare":0,"Master":1, "Miss":2, "Ms" : 2 , "Mme":2, "Mlle":2, "Mrs":2, "Mr":3,"Dr":3})

sns.barplot(x = dataset["Title"],y = dataset["Survived"])

dataset["Title"].unique()

dataset.drop(labels= ["Name"],axis = 1 ,inplace =True)#将name列丢掉

dataset = pd.get_dummies(dataset,columns = ["Title"])#将title列给分列

1349782-20180903113653856-1580034559.png

1349782-20180903113050956-1923292857.png

1.2.7 Cabin

客舱号代表着所处船上的位置,可能不同的客舱位置跑到救援船上的几率有一定的相关性

缺失的客舱可能是没有客舱,统一替换为X

有客舱的整体来说比没有客舱的获救几率更高些

#Cabin

dataset["Cabin"]=pd.DataFrame([i[0] if not pd.isnull(i) else "X" for i in dataset["Cabin"]])#可以考虑加入客舱号字母后面的数字,可能有些数字里逃生口较近

dataset.Cabin.unique()

sns.barplot(x=dataset["Cabin"],y=dataset["Survived"])

dataset= pd.get_dummies(dataset,columns = ["Cabin"])

1349782-20180903120117271-1127052756.png

1.2.8 Embarked

从图中看出登船港口不同之间的获救几率差别不大,客人登船后基本都会到自己的客舱,猜测是不同的登船港口会分有无客舱或者船票类别登船,但是对是否获救影响不大

sns.barplot(x=train["Embarked"],y=train["Survived"])

1349782-20180903120451055-1384290665.png

1.2.9 Ticket

#Ticket

Ticket =[]for i inlist(dataset.Ticket):if noti.isdigit():

Ticket.append(i.replace(".","").replace("/","").strip().split(" ")[0])else:

Ticket.append("X")#按船票的字母和数字将船票区分

dataset["Ticket"] =Ticket

dataset.Ticket.unique()

dataset= pd.get_dummies(dataset,columns = ["Ticket"],prefix = "T")#prefix将Ticket改名

1349782-20180903122159079-229883581.png

2 特征工程

2.1 Age Sex

年龄会跟父母和兄弟姐妹有很大关系,因此将SibSp,Parch,Pclass一样的平均值做为部分填充

其余填充剩余值的平均值,并将sex转化为0 1 数值型

将年龄分段

#Age填充#获取age缺失值的索引列表

index_nan_age = list(dataset["Age"][dataset.Age.isnull()].index)#print(index_nan_age)

for i inindex_nan_age:

age_med= dataset["Age"].median()

age_smed= dataset["Age"][((dataset["SibSp"] == dataset.iloc[i]["SibSp"])&(dataset["Parch"] == dataset.iloc[i]["Parch"])&(dataset["Pclass"] == dataset.iloc[i]["Pclass"]))].median()#取家人乘客等级相同的age平均值进行填充,其余用总平均值填充

if notnp.isnan(age_smed):

dataset["Age"].iloc[i] =age_smed#这里flag 为什么一定要用[]

else:

dataset["Age"].iloc[i] =age_med#dataset.info()

#Sex数值转换

dataset["Sex"] = dataset["Sex"].replace("male",1)

dataset["Sex"] = dataset["Sex"].replace("female",0)

dataset["Age"]=dataset["Age"].astype(int)

dataset["Age_1"] = dataset["Age"].map(lambda x : 1 if x<=11 else0)

dataset["Age_2"] = dataset["Age"].map(lambda x : 1 if x>11 & x<=18 else0)

dataset["Age_3"] = dataset["Age"].map(lambda x : 1 if x>18 & x<=22 else0)

dataset["Age_4"] = dataset["Age"].map(lambda x : 1 if x>22 & x<=27 else0)

dataset["Age_5"] = dataset["Age"].map(lambda x : 1 if x>27 & x<=33 else0)

dataset["Age_6"] = dataset["Age"].map(lambda x : 1 if x>33 & x<=40 else0)

dataset["Age_7"] = dataset["Age"].map(lambda x : 1 if x>40 else0)

dataset.drop(labels= ["Age"],axis = 1,inplace = True)

2.2 Name

取名字的称呼分别对其分类,以便能将其作为特征代入模型

#name处理#dataset["Name"].sample(10)

name_list = [i.split(",")[1].split(".")[0].strip() for i in dataset["Name"]]#按指定字符将字符串切片为列表

dataset["Title"] =pd.DataFrame(name_list)

g= sns.countplot(dataset["Title"])

g= plt.setp(g.get_xticklabels(),rotation=45)

dataset["Title"] = dataset["Title"].replace(['Lady', 'the Countess','Countess','Capt','Col','Don', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'],"rare")#dataset["Title"] = dataset["Title"].map({"rare":0,"Master":1, "Miss":2, "Ms" : 2 , "Mme":2, "Mlle":2, "Mrs":2, "Mr":3,"Dr":3})

sns.barplot(x = dataset["Title"],y = dataset["Survived"])

dataset["Title"].unique()

dataset.drop(labels= ["Name"],axis = 1 ,inplace =True)#将name列丢掉

dataset = pd.get_dummies(dataset,columns = ["Title"])#将title列给分列

2.3 SibSp Parch

按家庭人数将其分为4个特征

#家人

dataset["Fsize"] = dataset["SibSp"] + dataset["Parch"] + 1sns.barplot(x= dataset["Fsize"],y = dataset["Survived"])

dataset['Single'] = dataset['Fsize'].map(lambda s: 1 if s == 1 else0)

dataset['SmallF'] = dataset['Fsize'].map(lambda s: 1 if s == 2 else0)

dataset['MedF'] = dataset['Fsize'].map(lambda s: 1 if 3 <= s <= 4 else0)

dataset['LargeF'] = dataset['Fsize'].map(lambda s: 1 if s >= 5 else0)#家庭人数为2-3人存活几率更大些

dataset = pd.get_dummies(dataset, columns = ["Fsize"])

2.4

同样将票价分为多个类别

#Fare

dataset["Fare"]=dataset['Fare'].replace(np.nan,dataset["Fare"].median())#dataset["Fare"].describe()

dataset["Fare_1"] = dataset["Fare"].map(lambda x : 1 if x<=7.91 else0)

dataset["Fare_2"] = dataset["Fare"].map(lambda x : 1 if x>7.91 and x<=14.454 else0)

dataset["Fare_3"] = dataset["Fare"].map(lambda x : 1 if x>14.454 and x<=99 else0)

dataset["Fare_4"] = dataset["Fare"].map(lambda x : 1 if x>99 and x<=250 else0)

dataset["Fare_5"] = dataset["Fare"].map(lambda x : 1 if x>250 else0)

dataset.drop(labels= ["Fare"],axis = 1,inplace = True)

3 特征选择

通过逐个测试特征存在与否,观察某个特征有无对准确率的影响,进而筛选出表现好的特征

#特征工程

train =dataset[:train_len]

test=dataset[train_len:]

test.drop(labels=["Survived"],axis = 1,inplace=True)

feature=train.columns.values.tolist()

feature.remove("Survived")

x=np.array(train[feature])

y= np.array(train["Survived"])

from sklearn.model_selection importcross_val_scorefrom sklearn importlinear_model

pre_features=[]

rest_features=feature[:]

best_acc=0while len(rest_features)>0:

temp_best_i= ''temp_best_acc=0for feature_i inrest_features:

temp_features= pre_features +[feature_i,]

x=train[temp_features]

scores= cross_val_score(rf,x,y,cv=5 , scoring='accuracy')

acc=np.mean(scores)if acc >temp_best_acc:

temp_best_acc=acc

temp_best_i=feature_iprint("select",temp_best_i,"acc:",temp_best_acc)if temp_best_acc >best_acc:

best_acc=temp_best_acc

pre_features+=[temp_best_i,]

rest_features.remove(temp_best_i)else:break

#print("best feature set: ",selected_features,"acc: ",best_acc)

print(pre_features)

4 模型融合-投票法

采用多个算法模型进行投票,少数服从多数

from sklearn importlinear_modelfrom sklearn.neighbors importKNeighborsClassifierfrom sklearn.svm importSVCfrom sklearn importtreeknn_est = KNeighborsClassifier(n_neighbors = 2)svm_est = SVC(kernel='linear', C=0.025)dt_est = tree.DecisionTreeClassifier(max_depth=8)ab_est = ensemble.AdaBoostClassifier(n_estimators=500, learning_rate=0.1)rf_est = ensemble.RandomForestClassifier(n_estimators=500, warm_start=True,max_features='sqrt',max_depth=6,min_samples_split=3,min_samples_leaf=2, n_jobs=-1, verbose=0)gbm_est = ensemble.GradientBoostingClassifier(n_estimators=500, learning_rate=0.008,min_samples_split=3, min_samples_leaf=2,max_depth=5, verbose=0)et_est = ensemble.ExtraTreesClassifier(n_estimators=500, n_jobs=-1, max_depth=8, min_samples_leaf=2, verbose=0)lm_set = linear_model.LogisticRegression()voting_est = ensemble.VotingClassifier(estimators = [('rf', rf_est),('gbm', gbm_est),('et', et_est),("lm",lm_set),("dt",dt_est),("ab",ab_est),("knn",knn_est),("svm",svm_est)],voting = 'hard',n_jobs = 50)voting_est.fit(x,y)

from sklearn.model_selection importcross_val_score

scores= cross_val_score(voting_est,x,y,cv = 5,scoring = "accuracy")print(np.mean(scores))

1349782-20180903133316374-7311919.png

5 预测

预测测试集

voting_est = voting_est.fit(train[pre_features],train["Survived"])

predict_data=voting_est.predict(test[pre_features])

submission= pd.DataFrame({"PassengerId":testId,"Survived":predict_data})

submission.to_csv("G:\\titanic\\voting_est.csv",index = False)

6 总结

最后训练出来的模型在训练集上进行交叉检验准确率平均为85%,但是用来实际预测测试集时准确率仅有76%。回顾整个项目解决流程,特征工程很重要,发掘选择正确的特征才是提高准确度的基础。训练模型是为精髓,自己对这部分知之甚少,本次项目模型调参未涉及,模型融合用了最简单的投票法,stacking、blending等也都未涉及,以及模型是否过拟合或者欠拟合没有进行探讨。最后,需要学习的东西还很多,这已经是个不错的开始。

前途艰辛,仍需砥砺前行!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值