学习了数据分析之后,由于忙着准备毕业课题,没有时间记录数据分析的项目。泰坦尼克号生存预测是Kaggle上的经典竞赛项目。在泰坦尼克号的乘客中有男有女,有老有幼,有社会上流人士,也有底层群众。在救人的时候并不是随机的,我们利用乘客信息分析获救乘客的规律。一开始代码是在IDLE下编写的,后面为了展示每一步的结果,重新转到了Jupyter notebook下,做数据分析非常方便。
源代码我已经上传到Github,GitHub - missbai119/Code at Kaggle_titanic
项目链接:Titanic: Machine Learning from Disaster | Kaggle
一、思路
1.数据获取
2.数据观察
3.数据清洗
4.建立模型并预测
1.数据获取
数据在Kaggle中直接进行下载,包括训练集(train.csv)及测试集(test.csv),数据下载地址链接:https://www.kaggle.com/c/titanic/data
2.数据观察
导入数据
pandas是常用的Python数据处理库,读入的csv文件转为dataframe格式,可以看到读入的data_train数据如下,共有891行数据:
数据中共有12列,Survived字段表示该乘客是否获救,其余为乘客信息,包括:
PassengerId--乘客Id
Pclass--乘客等级(1/2/3等舱)
Name--乘客姓名
Sex--性别
Age--年龄
SibSp--堂兄弟/妹个数
Parch--父母与小孩个数
Ticket--船票信息
Fare--票价
Cabin--客舱
Embarked--登船港口
用data_train.info()观察数据的属性,由此可知共有891名乘客,数据中有一些缺失值,Cabin有非常多的缺失值。
利用data_train.describe()再获得数据型数据的分布情况,加深对数据的认识,对数据的认识是数据分析的关键。
乘客的属性很多,我们的目标是分析属性和最后Survived之间存在怎样的关系。
我们需要借助图来观察乘客属性与结果之间的关系,将乘客属性信息借助图来展示
由上面的图可以看出一些信息,比如获救人数不到总数的一半;三等舱的人数最多,并且二等舱、三等舱的乘客20到30岁的乘客最多,头等舱里40岁左右的人最多;登船港口S人数最多,且S,C,Q人数递减。
思考一下:不同舱的乘客可能与财富或社会地位有关,最后获救的可能性会不会不一样;年龄与最后是否获救应该也有影响;是否获救和登船港口有没有关系,也许登船港口与社会地位和财富有关系。
接下来分析一下各个等级的乘客获救情况
由上图可以看出,头等舱的乘客获救概率最高,三等舱获救概率很低,因此乘客等级与是否获救有关系。
分析一下性别与获救的关系
由此图可以看出,女性获救概率比男性高。
3.数据清洗
数据中缺失值比较严重的Cabin,按照有无数据处理为Yes和No两种类型。Age也有一些缺失,并且年龄对最后结果有影响。数据中Age确实的个数不是特别多,可以根据已有的数据值,拟合补全数据。采用scikit-learn中的RandomForest来拟合缺失的年龄数值。
建立逻辑回归模型需要将数据转化为数值型特征
Age和Fare两个属性的数值幅度有点大,会影响收敛速度,对两个属性处理一下
4.建立逻辑回归模型
对test_data同样需要数据处理
预测结果保存在本地为csv格式
要判定一下当前模型所处状态(欠拟合/过拟合)
如果我们不断地做feature engineering,产生的特征越来越多,再用这些特征去训练模型,训练数据拟合的很好,然而模型的泛化能力逐渐弱化,就会在预测数据上准确率不高,即模型的过拟合问题。
此外,如果模型在训练数据上准确率不高,也有可能是出现了欠拟合问题。
通常,对于过拟合现象会挑选出比较好的feature的子集来做训练或提供更多的训练数据。对于欠拟合问题,通常需要更多的特征,更复杂的模型提高准确率。
learning curve可以帮助我们判定模型所处的状态。以样本数为横坐标,训练和交叉验证集上的错误率为纵坐标,也可以把错误率替换成准确率。
用scikit-learn里面的learning_curve来帮我们分辨模型的状态。
交叉验证
交叉验证是指将数据分成大小相同的k份,在每次运行中选取其中一份作为检查集,其余的全作为训练集,该过程重复k次,使得每份数据都用于检验恰好一次。
在本例中我们把train.csv分成两部分,一部分用于训练模型,另一部分数据用于预测算法的效果。
大家可以自己跑一遍试试,拿到bad cases之后,仔细看看。也会有一些猜测和想法。其中会有一部分可能会印证在系数分析部分的猜测,那这些优化的想法优先级可以放高一些。
现在有了”train_df” 和 “vc_df” 两个数据部分,前者用于训练model,后者用于评定和选择模型。可以开始可劲折腾了。
随便列一些可能可以做的优化操作:
Age属性不使用现在的拟合方式,而是根据名称中的『Mr』『Mrs』『Miss』等的平均值进行填充。
Age不做成一个连续值属性,而是使用一个步长进行离散化,变成离散的类目feature。
Cabin再细化一些,对于有记录的Cabin属性,我们将其分为前面的字母部分(我猜是位置和船层之类的信息) 和 后面的数字部分(应该是房间号,有意思的事情是,如果你仔细看看原始数据,你会发现,这个值大的情况下,似乎获救的可能性高一些)。
Pclass和Sex俩太重要了,我们试着用它们去组出一个组合属性来试试,这也是另外一种程度的细化。
单加一个Child字段,Age<=12的,设为1,其余为0(你去看看数据,确实小盆友优先程度很高啊)
如果名字里面有『Mrs』,而Parch>1的,我们猜测她可能是一个母亲,应该获救的概率也会提高,因此可以多加一个Mother字段,此种情况下设为1,其余情况下设为0
登船港口可以考虑先去掉试试(Q和C本来就没权重,S有点诡异)
把堂兄弟/兄妹 和 Parch 还有自己 个数加在一起组一个Family_size字段(考虑到大家族可能对最后的结果有影响)
Name是一个我们一直没有触碰的属性,我们可以做一些简单的处理,比如说男性中带某些字眼的(‘Capt’, ‘Don’, ‘Major’, ‘Sir’)可以统一到一个Title,女性也一样。
可以使用手头上的”train_df”和”cv_df”开始试验这些feature engineering的tricks是否有效了。
试验的过程比较漫长,也需要有耐心,而且我们经常会面临很尴尬的状况,就是我们灵光一闪,想到一个feature,然后坚信它一定有效,结果试验下来,效果还不如试验之前的结果。
从得到的学习曲线来看,虽然不光滑,训练集和交叉验证集上的得分曲线走势符合预期。目前的曲线来看,我们的模型不处于过拟合状态,一次我们可以再做一些特征工程的工作,添加一些新的特征或组合特征到模型中。
模型融合(model ensemble)
比如我们手头上有一堆在同一份数据集上训练得到的分类器(比如logistic regression,SVM,KNN,random forest,神经网络),那我们让他们都分别去做判定,然后对结果做投票统计,取票数最多的结果为最后结果。
现在我们没有别的模型可选,可以在数据上做改动。不用全部的数据都用于训练,而是每次选训练集的一个子集做训练,虽然用同一个算法,但得到的模型却是不一样的,即使出现过拟合现象,也只是在一个子训练集上出现过拟合,这就是常用的Bagging.