Titanic生还率预测

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读取测试集和训练集的数据,并简单查看训练集的数据特点,重点了解有那些特征以及有多少数据缺失。

 PassengerIdSurvivedPclassNameSexAgeSibSpParchTicketFareCabinEmbarked
0103Braund, Mr. Owen Harrismale22.010A/5 211717.2500NaNS
1211Cumings, Mrs. John Bradley (Florence Briggs Th...female38.010PC 1759971.2833C85C

 PassengerIdSurvivedPclassAgeSibSpParchFare
count891.000000891.000000891.000000714.000000891.000000891.000000891.000000
mean446.0000000.3838382.30864229.6991180.5230080.38159432.204208
std257.3538420.4865920.83607114.5264971.1027430.80605749.693429
min1.0000000.0000001.0000000.4200000.0000000.0000000.000000
25%223.5000000.0000002.00000020.1250000.0000000.0000007.910400
50%446.0000000.0000003.00000028.0000000.0000000.00000014.454200
75%668.5000001.0000003.00000038.0000001.0000000.00000031.000000
max891.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=0
for i in range(2):
	for j in range(3):
		if start==len(plain_features):
			break
		Survived_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_1
data['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']=0
data.loc[(data['Age'] > 16) & (data['Age'] <= 32), 'Age'] = 1
data.loc[(data['Age'] > 32) & (data['Age'] <= 48), 'Age'] = 2
data.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.Parch
data.loc[data.Family>0,'Family']=1
data.loc[data.Family==0,'Family']=0
data.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.Survived
X_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.0
	else:
		retarray[datamatrix[:,dimen]>threshval]=-1.0
	return retarray

def buildstump(dataarr,classlabels,D):
	datamatrix=mat(dataarr);labelmat=mat(classlabels).T
	m,n=shape(datamatrix)
	numstep=10.0;beststump={};bestclasest=mat(zeros((m,1)))
	minerror=inf
	for i in range(n):
		rangemin=datamatrix[:,i].min();rangemax=datamatrix[:,i].max()
		stepsize=(rangemax-rangemin)/numstep
		for 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]=0
				weightederror=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=weightederror
					bestclasest=predictedvals.copy()
					beststump['dim']=i
					beststump['thresh']=threshval
					beststump['ineq']=inequal
	return 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.T
		alpha=float(0.5*log((1.0-error)/max(error,1e-16)))
		beststump['alpha']=alpha
		weakclassarr.append(beststump)
		#print"classest:",classest.T
		expon=multiply(-1*alpha*mat(classlabels).T,classest)
		D=multiply(D,exp(expon))
		D=D/D.sum()
		aggclassest+=alpha*classest
		#print"aggclassest:",aggclassest.T
		aggerrors=multiply(sign(aggclassest)!=mat(classlabels).T,ones((m,1)))
		errorrate=aggerrors.sum()/m
		#print"total error:",errorrate,"\n"
		if errorrate==0.0:break
	return 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 aggclassest
	return sign(aggclassest)
打印出不同迭代次数的训练错误率

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


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值