Titanic生还率预测

来源:互联网 发布:大数据世界txt下载 编辑:程序博客网 时间:2024/04/26 09:23
Titanic生还率预测是Kaggle的经典项目,最近学习了机器学习与数据分析相关算法,参考了Kaggle里一些Kernels,通过此项目来锻炼自己所学的知识。
主要使用Python语言里的pandas、sk-learn、matplotlib包进行相关数据分析。
主要分析思路分为四个部分:导入数据、数据可视化、数据整理、调用算法预测。
一、导入数据
#导入数据,简单查看数据特点af=pd.read_csv(r'C:\software\workspace\Titanic\test.csv')tf=pd.read_csv(r'C:\software\workspace\Titanic\train.csv')print tf.head(2) #查看前2行数据print tf.describe() #显示所有特征值的统计信息print tf.isnull().sum() #显示数据的缺失数量
首先使用pandas读取测试集和训练集的数据,并简单查看训练集的数据特点,重点了解有那些特征以及有多少数据缺失。

 PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C

 PassengerIdSurvivedPclassAgeSibSpParchFarecount891.000000891.000000891.000000714.000000891.000000891.000000891.000000mean446.0000000.3838382.30864229.6991180.5230080.38159432.204208std257.3538420.4865920.83607114.5264971.1027430.80605749.693429min1.0000000.0000001.0000000.4200000.0000000.0000000.00000025%223.5000000.0000002.00000020.1250000.0000000.0000007.91040050%446.0000000.0000003.00000028.0000000.0000000.00000014.45420075%668.5000001.0000003.00000038.0000001.0000000.00000031.000000max891.0000001.0000003.00000080.0000008.0000006.000000512.329200
可以看到训练数据共有12个特征值,891条
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
在这些数据中一共有3个特征值存在缺失值,分别是Age、Cabin和Emarked
二、数据可视化
1.每个特征与获救人数之间的简单柱状图显示
plain_features=['Pclass', 'Sex', 'SibSp', 'Parch', 'Embarked']fig,axes=plt.subplots(2,3,figsize=(20,10))plt.subplots_adjust(wspace=0.2,hspace=0.2)start=0for i in range(2):for j in range(3):if start==len(plain_features):breakSurvived_0=tf[plain_features[start]][tf.Survived==0].value_counts()Survived_1=tf[plain_features[start]][tf.Survived==1].value_counts()sf=pd.DataFrame({u'获救':Survived_1,u'未获救':Survived_0})sf.plot(kind='bar',ax=axes[i,j],stacked=True)start+=1#年龄与乘客等级密度曲线axes[1,2]=tf.Age[tf.Pclass==1].plot(kind='kde')axes[1,2]=tf.Age[tf.Pclass==2].plot(kind='kde')axes[1,2]=tf.Age[tf.Pclass==3].plot(kind='kde')axes[1,2]=plt.xlabel(u"年龄")axes[1,2]=plt.ylabel(u"密度")axes[1,2]=plt.title(u"各等级的乘客年龄分布")plt.show()

从图中可以简单了解乘客等级、性别、是否有家属、上船港口与获救情况的大致关系:
乘客等级越高获救比例越大;女性获救比例高于男性;有家属人数占总人数比例较小,且获救比例约为1:1,家属对获救情况影响不大;从S港口登船人数最多,获救人数占了1/3,C和Q港口人数较少,获救比例约为1/2和1/3,可以猜测等级为1的乘客大部分可能在C港上船;年龄与乘客等级存在一定关系,乘客等级较高的人年龄高于较低等级的乘客。因此基本可以判断对获救情况影响较大的几个特征为性别、乘客等级、年龄。下面就根据这几个特征对数据进行整理。
二、数据整理
训练数据中有大量字符型数据和缺失数据,需要将字符型数据转换成数值型,缺失数据进行填充或去除。
1. 姓名特征整理
从特征中可以看出姓名中的头衔可以大致判断乘客类别,因此把他们抽取出来并观察:
data=tf.copy()data['Title']=data['Name'].str.extract('([A-Za-z]+)\.',expand=False)print (collections.Counter(data['Title']).most_common())print ('\n')af['Title']=data['Name'].str.extract('([A-Za-z]+)\.',expand=False)print (collections.Counter(af['Title']).most_common())

将这些头衔整合成为4类Mr、Mrs、Miss、titled,并转换成整数:
data['Title'].replace(['Master','Major', 'Capt', 'Col','Don', 'Sir', 'Jonkheer', 'Dr'], 'titled', inplace = True)data['Title'].replace(['Countess','Lady'], 'Mrs', inplace = True)data['Title'].replace(['Mme'], 'Mrs', inplace = True)data['Title'].replace(['Mlle','Ms'], 'Miss', inplace = True)
Title_mapping={'titled':1,'Mrs':2,'Miss':3,'Mr':4,'Rev':5}data['Title']=data['Title'].map(Title_mapping).astype(int)
2.年龄特征整理
首先填充缺失的年龄数据,计算均值和方差,然后再将范围(Agemean-Agestd,Agemean+Agestd)的随机值填充到缺失值中;
然后将年龄均分为5个部分,并分别用0,1,2,3,4这5个整数值代替
Agemean=mean(data.Age)Agestd=data['Age'].std()Agenan=data['Age'].isnull().sum()rand_1=np.random.randint(Agemean-Agestd,Agemean+Agestd,size=Agenan)data.loc[data.Age.isnull(),'Age']=rand_1data['Age']=data['Age'].astype(int)#print data.Age.isnull().sum()#将年龄分为5个部分#data['AgeBand'] = pd.cut(data['Age'], 5)#AgeBand_result = data[['AgeBand', 'Survived']].groupby(['AgeBand'], as_index=False).mean().sort_values(by='AgeBand', ascending=True)#print AgeBand_result#data = data.drop(['AgeBand'], axis=1,inplace=True)data.loc[(data['Age'] <= 16),'Age']=0data.loc[(data['Age'] > 16) & (data['Age'] <= 32), 'Age'] = 1data.loc[(data['Age'] > 32) & (data['Age'] <= 48), 'Age'] = 2data.loc[(data['Age'] > 48) & (data['Age'] <= 64), 'Age'] = 3
data.loc[data['Age'] > 64, 'Age']=4
3.乘船港口、性别、费用特征整理
将这几个特征的缺失值填充并转化成数值型数据
Embarked_mapping={'S':1,'C':2,'Q':3}data.Embarked=data.Embarked.map(Embarked_mapping)data.loc[data['Embarked'].isnull(), 'Embarked'] = max(data.Embarked,key=data.Embarked.count)
data.Sex=data.Sex.map({'female':1,'male':0}).astype(int)
faremean=mean(data.Fare)data.loc[data.Fare.isnull(),'Fare']=float(faremean)
4.SibSp和Parch特征整合
将这两个特征值整合成Family这一个特征
data['Family']=data.SibSp+data.Parchdata.loc[data.Family>0,'Family']=1data.loc[data.Family==0,'Family']=0data.drop(['SibSp','Parch'],axis=1,inplace=True)
5.去除多余的特征
data.drop(['PassengerId','Name','Ticket','Cabin'],axis=1,inplace=True)
print data.head(5)
#print data.describe()#print data.isnull().sum()
四、调用算法预测
首先将测试集也按数据集的方法处理数据。
从sk-learn包调用算法进行预测
#调用逻辑回归包X_train=data.drop('Survived',axis=1)Y_train=data.SurvivedX_test=df.copy()logreg = LogisticRegression()logreg.fit(X_train, Y_train)Y_pred = logreg.predict(X_test)print logreg.score(X_train, Y_train)pdata={'PassengerId':af.PassengerId,'Survived':Y_pred}solution=pd.DataFrame(pdata)solution.to_csv('rf_solution.csv',index=False)#随机森林random_forest = RandomForestClassifier(n_estimators=100)random_forest.fit(X_train, Y_train)Y_pred = random_forest.predict(X_test)print random_forest.score(X_train, Y_train)pdata={'PassengerId':af.PassengerId,'Survived':Y_pred}solution=pd.DataFrame(pdata)solution.to_csv('rf_solution.csv',index=False)
得分别为0.807和0.94,因此将随机森林的预测结果存入文件中上传到Kaggle。
最终在Kaggle上得分0.7655。
还需要进一步优化数据提高正确率,尽可能减少数据中那些无效的变量,另外也需要对数据分布有一定的感知能力,需要加强统计知识方面的学习,在这方面还有待提高。
另外,还有一些特征值直接去除了(比如Cabin),没有进一步挖掘,一些填充值也许有更好的处理办法,后续还有很多的细节工作处理,今天就先到这里吧。
为了进一步提高分类性能,参考《机器学习实战》中Adaboost算法训练数据,算法使用多个单层决策树分类器加权求和以得到更高的分类性能:
#单层决策树生成函数def stumpcalssify(datamatrix,dimen,threshval,threshIneq):retarray=ones((shape(datamatrix)[0],1))if threshIneq=='1t':retarray[datamatrix[:,dimen]<=threshval]=-1.0else:retarray[datamatrix[:,dimen]>threshval]=-1.0return retarraydef buildstump(dataarr,classlabels,D):datamatrix=mat(dataarr);labelmat=mat(classlabels).Tm,n=shape(datamatrix)numstep=10.0;beststump={};bestclasest=mat(zeros((m,1)))minerror=inffor i in range(n):rangemin=datamatrix[:,i].min();rangemax=datamatrix[:,i].max()stepsize=(rangemax-rangemin)/numstepfor j in range(-1,int(numstep)+1):for inequal in ['1t','gt']:threshval=(rangemin+float(j)*stepsize)predictedvals=stumpcalssify(datamatrix,i,threshval,inequal)errarr=mat(ones((m,1)))errarr[predictedvals==labelmat]=0weightederror=D.T*errarr#print "split:dim %d,thresh %.2f,thresh inequal: %s,the weighted error is: %.3f" %(i,threshval,inequal,weightederror)if weightederror<minerror:minerror=weightederrorbestclasest=predictedvals.copy()beststump['dim']=ibeststump['thresh']=threshvalbeststump['ineq']=inequalreturn beststump,minerror,bestclasest#基于单层决策树的adaboost训练过程def adaboostTrainDS(dataarr,classlabels,numit=40):weakclassarr=[]m=shape(dataarr)[0]D=mat(ones((m,1))/m)aggclassest=mat(zeros((m,1)))for i in range(numit):beststump,error,classest=buildstump(dataarr,classlabels,D)#print"D:",D.Talpha=float(0.5*log((1.0-error)/max(error,1e-16)))beststump['alpha']=alphaweakclassarr.append(beststump)#print"classest:",classest.Texpon=multiply(-1*alpha*mat(classlabels).T,classest)D=multiply(D,exp(expon))D=D/D.sum()aggclassest+=alpha*classest#print"aggclassest:",aggclassest.Taggerrors=multiply(sign(aggclassest)!=mat(classlabels).T,ones((m,1)))errorrate=aggerrors.sum()/m#print"total error:",errorrate,"\n"if errorrate==0.0:breakreturn weakclassarr#Adaboost分类函数def adaClassify(datatoclass,classifierArr):datamatrix=mat(datatoclass)m=shape(datamatrix)[0]aggclassest=mat(zeros((m,1)))for i in range(len(classifierArr)):classest=stumpcalssify(datamatrix,classifierArr[i]['dim'],classifierArr[i]['thresh'],classifierArr[i]['ineq'])aggclassest+=classifierArr[i]['alpha']*classest#print aggclassestreturn sign(aggclassest)
打印出不同迭代次数的训练错误率

变化不是很明显,可能原因是数据比较简单,较小的迭代次数就满足要求了
dataMat=data.drop('Survived',axis=1)data.loc[data['Survived']==0,'Survived']=-1labelMat=data['Survived']testMat=dftestlabelMat=labelMatclassifierArray=adaboost.adaboostTrainDS(dataMat,labelMat,10)prediction10=adaboost.adaClassify(testMat,classifierArray)errArr=mat(ones((len(testlabelMat),1)))errRate=errArr[prediction10!=mat(testlabelMat).T].sum()/len(testlabelMat)#print errRatepred=[]for i in range(len(prediction10)):if prediction10[i]==-1:pred.append(0)else: pred.append(1)#print predpdata={'PassengerId':af.PassengerId,'Survived':pred}solution=pd.DataFrame(pdata)solution.to_csv('rf_solution.csv',index=False)
将预测结果上传到Kaggle,得分0.77033,果然有所提高,但是不是特别明显。看来要想提高得分还是得从数据本身入手,对数据进行更深层次挖掘。


原创粉丝点击