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

  PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C

  PassengerId Survived Pclass Age SibSp Parch Fare
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.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()

Titanic生还率预测_第1张图片
从图中可以简单了解乘客等级、性别、是否有家属、上船港口与获救情况的大致关系:
乘客等级越高获救比例越大;女性获救比例高于男性;有家属人数占总人数比例较小,且获救比例约为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
打印出不同迭代次数的训练错误率

变化不是很明显,可能原因是数据比较简单,较小的迭代次数就满足要求了
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,果然有所提高,但是不是特别明显。看来要想提高得分还是得从数据本身入手,对数据进行更深层次挖掘。


你可能感兴趣的:(python)