kaggle_Titanic幸存预测

kaggle_Titanic幸存预测

介绍

简单介绍一下Titanic幸存预测这个项目,出自kaggle,下载的数据集有两个,训练数据集Train.csv和测试数据集test.csv。其中Train.csv中有12列代表乘客的信息,test.csv中有11列,相对于Train.csv少了Survived,其中Survived就是我们需要预测的。这里首先会对数据进行一个初步的认识,通过可视化工具直观的看看各特征和Survived之间的关系。再对数据进行预处理,包括缺失值处理、数据标准化、异常数值处理等。第三步为特征工程,最后选取特征进行建模预测和模型的融合。

1.数据的认识

首先我们通过pandas读入train.csv和test.csv两个文件,前者为训练集,后者为训练集

import pandas as pd 

data_train = pd.read_csv("E:\\kaggle\\ttnk\\Train.csv")
data_test = pd.read_csv("E:\\kaggle\\ttnk\\test.csv")
data_train.info()
print('-'*50)
data_test.info()

看看结果
结果
可以看出train.csv(训练集)中有12个特征,其中浮点和整形有7个,object类型有5个。其中有三个特征(age,cabin,embarked)存在缺失值。乘客数量有891名。
test.csv(测试集)中有11个特征,相比训练集少了survived(幸存),这也是我们需要预测的,其中有三个特征(age,fare,cabin)存在缺失值。乘客数量有418名。

下面给出各特征的中文含义

项目Value
PassengerId乘客ID
Pclass仓位等级
Name姓名
Sex性别
Age年龄
SibSp一同上船的兄弟/妹个数
Parch父母与小孩个数
Ticket船票信息
Fare票价
Cabin客舱
Embarked登船港口

我们先通过可视化看看各特征之间的关系:

1.1 pclass与survivedz之间的关系

data_train[['Pclass','Survived']].groupby(['Pclass']).mean().plot.bar()
plt.xlabel("Pclass")  
plt.show()

结果1
可以看出一等舱的获救比例超过0.6,二、三等舱获救率依次递减。所以Survived与pclass有一定的关系。

1.2 sex与survived之间的关系

data_train[['Sex','Survived']].groupby(['Sex']).mean().plot.bar()
plt.xlabel("Sex")  
plt.show()

结果2
能看出船上的男性在危难面前还是很值得敬佩的,所以sex对于survived是一个重要的特征。

1.3 年龄在各船舱之间的分布

data_train.Age[data_train.Pclass == 1].plot.kde()  
data_train.Age[data_train.Pclass == 2].plot.kde()
data_train.Age[data_train.Pclass == 3].plot.kde()
plt.xlabel('age')
plt.title('age distribution')
plt.legend(('1', '2', '3'),loc='best')
plt.show()

结果3
从图中可以看出三等舱的年龄大部分都在20几岁,二等舱的年龄大部分布在30岁,而一等舱40岁左右的人最多。这也符合我们的经验。

1.4 fare(票价)与survived的关系

我们首先通过excel对fare进行排序来观察数据

结果4
有15位乘客的票价为0,只有一位存活,都为男性,上船地点都为s。结合实际情况我们可以认为这些乘客有很大的可能是船上的工作人员。(0,10.5)这个价格区间的都为三等舱,(75,512)这个价格区间的乘客都为一等舱。所以在做特征工程上可以将票价信息划分为0,(0,10.5),[10.5,75],(75,512)四个范围,对fare离散化处理。

1.5 关于name的观察

可以看出,乘客姓名是有一定格式的,其中有一个关于称谓的词,大致可以分为四类
1、‘miss’表示年轻未婚女子
2、‘master’表示小男孩
3、’mrs‘表示女士
4、‘mr’表示男士(文中还有少数rev、dr都归为这一类)
显然这些称谓和年龄有很大的相关性

1.6 Embarked(上船地点)与survived的关系

data_train[['Embarked','Survived']].groupby(['Embarked']).mean().plot.bar()
plt.xlabel("Embarked")  
plt.show()

结果5

2特征工程

2.1缺失值的处理

缺失值处理一般一下几种方法:
(1)如果缺值的样本占总数比例极高,可能就直接舍弃。
(2)如果缺值的样本适中,而该属性非连续值特征属性(比如说类目属性),那就把NaN作为一个新类别,加到类别特征中
(3)如果缺值的样本适中,而该属性为连续值特征属性,有时候我们会考虑给定一个step(比如这里的age,我们可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个type加到属性类目中。
(4)有些情况下,缺失的值个数并不是特别多,我们可以根据数据特点,将数据的均值、中位数或者众数进行填充。

2.1.1Embarked缺失值处理
data_train.Embarked.value_counts().plot(kind='bar')
plt.ylabel('count')
plt.xlabel('Embarked')
plt.show()

结果6
这里我们直接用众数填充

data_train_df = pd.read_csv("E:\\kaggle\\ttnk\\Train.csv")
data_test_df = pd.read_csv("E:\\kaggle\\ttnk\\test.csv")
data_test_df['Survived'] = 0
data_train_test = data_train_df.append(data_test_df)
PassengerId = data_test_df['PassengerId']
data_train_test['Embarked'].fillna(data_train_test['Embarked'].mode().iloc[0], inplace=True)
2.1.2 fare缺失值处理

票价的分布太广,所以我们将Fare进行离散化,其中有些乘客的票价为0,再综合其他信息可以初步预测这些人为船上的工作人员,而且这些人的死亡率极高。所以我们将0单独作为一个部分,(1,10.5],(10.5,75],(75,513]为其他三个区间,进行离散化,最后再factorize处理。

#以对应仓位的均值填充
data_train_test['Fare'] = data_train_test[['Fare']].fillna(data_train_test.groupby('Pclass').transform(np.mean))
fare_qujian=[0,1,10.5,75,513]
data_train_test['Fare'] = pd.cut(data_train_test['Fare'], fare_qujian)
data_train_test['Fare'] = pd.factorize(data_train_test['Fare'])[0]
#print(data_train_test.info())
2.1.3 cabin缺失值处理

Cabin缺失值过多,这里我们不考虑将cabin作为特征,所以不对其进行处理。

2.1.4 age缺失值处理

由上面的分析知道age是一个比较重要的特征,不能对其进行删除,由于其缺失的数量比较多,平均数和众数填充的方法也不合适,所以这里我们选择机器学习来预测其缺失值年龄。
这里,我们并不选择所有的特征对其进行预测,而是只选择Name,SibSp,Parch这三个特征来进行。因为对数据的观察认为这三个特征和年龄的相关性明显,通过Name,SibSp,Parch所预测的年龄也包含了这三个特征的大部分信息。所以在最后对生存的预测中将不考虑这三个特征,只取age来进行分析。
其中年龄是一个连续数据,对于获救的先后顺序,连续数据并不会带来太大的分析价值,加上年龄的跨度和分布还容易导致模型的收敛问题。所以这里我们将年龄划分为四个阶段分别为:少年(0,13],青年(13,30],中年(30,60],老年(60,80]。

首先对name进行处理

观察数据可以发现,乘客的Name也是有一定规则的,在外国人的称呼中会带一些表尊敬的助词,比如Miss(年轻未婚女子),Master(小于13岁的小男孩),Mr、Rev、Dr(通常是对男性的称谓),Mrs、Lady、Mme(代表女士)。所以这里将Name分为四类,用正则表达式匹配出来,再将其进行factorize或get_dummies处理。建立新的特征’Title’

data_train_test['Title'] = data_train_test['Name'].map(lambda x: re.compile(", (.*?)\.").findall(x)[0])
title_Dict = {}
title_Dict.update(dict.fromkeys(['Mr','Sir', 'Major', 'Dr', 'Rev','Jonkheer','capt'], 'Mr'))
title_Dict.update(dict.fromkeys(['Mme','mlle','Ms', 'Mrs', 'Lady', 'the Countess'], 'Mrs'))
title_Dict.update(dict.fromkeys(['Miss'], 'Miss'))
title_Dict.update(dict.fromkeys(['Master'], 'Master'))
data_train_test['Title'] = data_train_test['Title'].map(title_Dict)

将名字分为四类,再对Title进行factorize化

data_train_test['Title'] = pd.factorize(data_train_test['Title'])[0]

对Title进行factorize化后的结果
结果7

将非空的Age进行处理

首先我们对已有乘客的年龄划分为四个阶段(0,13,30,60,80),划分为四个阶段之后再对其factorize化处理,保存在Age_bin_id项中。同时选取对年龄预测特征,将数据划分为训练集和测试集

missing_age_df = pd.DataFrame(data_train_test[['Age', 'Title','SibSp','Parch']])
missing_age_train_test = missing_age_df[missing_age_df['Age'].notnull()]
qujian=[0,13,30,60,80]
missing_age_train_test['Age_bin'] = pd.cut(missing_age_train_test['Age'], qujian)
#print(missing_age_train_test.head())
missing_age_train_test['Age_bin_id'] = pd.factorize(missing_age_train_test['Age_bin'])[0]
#选取特征,数据划分为训练集和测试集
missing_age_train = pd.DataFrame(missing_age_train_test[['Age_bin_id', 'Title','SibSp','Parch']])
missing_age_test = missing_age_df[missing_age_df['Age'].isnull()]

结果8
这里还需要用Age_bin_id中的factorize型替换掉data_train_test中的Age项,同时我们来看看现在data_train_test中的数据头几行

data_train_test.loc[(data_train_test.Age.notnull()), 'Age'] =missing_age_train_test['Age_bin_id']
print(data_train_test.head())

在这里插入图片描述

对Age进行预测
from sklearn import model_selection
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.ensemble import RandomForestRegressor

def fill_missing_age(missing_age_train, missing_age_test):
    missing_age_X_train = missing_age_train.drop(['Age_bin_id'], axis=1)
    missing_age_Y_train = missing_age_train['Age_bin_id']
    missing_age_X_test = missing_age_test.drop(['Age'], axis=1)
    
    #随机森林
    rf_reg = RandomForestRegressor()
    rf_reg_param_grid = {'n_estimators': [200], 'max_depth': [5], 'random_state': [0]}
    rf_reg_grid = model_selection.GridSearchCV(rf_reg, rf_reg_param_grid, cv=5, n_jobs=25, verbose=1)
    rf_reg_grid.fit(missing_age_X_train, missing_age_Y_train)
    missing_age_test.loc[:, 'Age_RF'] = rf_reg_grid.predict(missing_age_X_test)
    #print(missing_age_test['Age_RF'][:10])

    #GDB
    gbm_reg = GradientBoostingRegressor(random_state=42)
    gbm_reg_param_grid = {'n_estimators': [1000], 'max_depth': [4], 'learning_rate': [0.01], 'max_features': [3]}
    gbm_reg_grid = model_selection.GridSearchCV(gbm_reg, gbm_reg_param_grid, cv=5, n_jobs=25, verbose=1)
    gbm_reg_grid.fit(missing_age_X_train, missing_age_Y_train)
    missing_age_test.loc[:, 'Age_GB'] = gbm_reg_grid.predict(missing_age_X_test)
    #print(missing_age_test['Age_GB'][:4])
    
    #模型融合
    missing_age_test['Age'] = missing_age_test[['Age_GB', 'Age_LR']].mode(axis=1)
    missing_age_test.loc[:, 'Age'] = np.mean([missing_age_test['Age_GB'], missing_age_test['Age_RF']])
    print(missing_age_test['Age'][:4]
    missing_age_test.drop(['Age_GB', 'Age_RF'], axis=1, inplace=True)
    return missing_age_test

将age的预测值填充在data_train_test中

data_train_test.loc[(data_train_test.Age.isnull()), 'Age'] = fill_missing_age(missing_age_train, missing_age_test)
2.1.5 最后对Ticket进行处理

船票信息看起来很杂,这里将纯数字的Ticket分为一类。再进行factorize处理

data_train_test['Ticket_Number'] = data_train_test['Ticket'].str.split().str[0]
data_train_test['Ticket_Number'] = data_train_test['Ticket_Number'].apply(lambda x: 'U0' if x.isnumeric() else x)
data_train_test['Ticket_Number'] = pd.factorize(data_train_test['Ticket_Number'])[0]

这里我们已经将所有的特征都处理完了,下面就可以选取需要的特征进行模型的预测

3 模型建立

首先将data_train_test进行一下备份,以备后续的分析。再选取我们需要的特征进行前期数据的准备工作

ttnk_data_train_test = data_train_test
data_train_test.drop(['PassengerId', 'Cabin', 'Name', 'Ticket'],axis=1,inplace=True)

将个data_train_test中的数据进行拆分成训练集和测试集

data_train = data_train_test[:891]
data_test = data_train_test[891:]

首先用LogisticRegression回归做预测,将结果保存在文件目录下。

#LogisticRegression
from sklearn import linear_modelfrom sklearn import model_selection
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn import linear_model
def LogisticRegression_predict_Survived(data_train, data_test):
    ttnk_data_train_X = data_train.drop(['Survived'],axis=1)
    ttnk_data_train_Y = data_train['Survived']
    ttnk_data_test_X = data_test.drop(['Survived'],axis=1)
    #from sklearn.ensemble import RandomForestClassifier
    clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
    clf.fit(ttnk_data_train_X, ttnk_data_train_Y)
    predictions = clf.predict(ttnk_data_test_X)
    result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
    result.to_csv("E:\\kaggle\\ttnk\\logistic_regression_predictions.csv", index=False)

再用随机森林进行预测

# RandomForest    
def RandomForest_predict_Survived(data_train, data_test):
    from sklearn.ensemble import RandomForestRegressor
    ttnk_data_train_X = data_train.drop(['Survived'],axis=1)
    ttnk_data_train_Y = data_train['Survived']
    ttnk_data_test_X = data_test.drop(['Survived'],axis=1)
    rf_est = RandomForestRegressor(random_state=0 , min_samples_split= 3 , max_depth = 20, n_jobs=25)
    rf_est.fit(ttnk_data_train_X, ttnk_data_train_Y)
    #print('Top N Features Best RF Params:' + str(rf_grid.best_params_))
    #print('Top N Features Best RF Score:' + str(rf_grid.best_score_))
    #print('Top N Features RF Train Score:' + str(rf_grid.score(titanic_train_data_X, titanic_train_data_Y)))
    predictions = rf_est.predict(ttnk_data_test_X)
    result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
    result.to_csv("E:\\kaggle\\ttnk\\RandomForest_predictions.csv", index=False)

通过两个模型得到的预测结果就可以向kaggle提交了,我们这里先不急着提交结果,看看kaggle竞赛就知道,往往排名靠前的的选手都非常重视模型融合,关于模型融合下面给大家介绍。

模型融合

常见的 Ensemble 方法有这么几种:
1、Bagging:使用训练数据的不同随机子集来训练每个 Base Model,最后进行每个 Base Model 权重相同的 Vote。也即 Random Forest 的原理。
2、Boosting:迭代地训练 Base Model,每次根据上一个迭代中预测错误的情况修改训练样本的权重。也即 Gradient Boosting,Adaboost 的原理。比 Bagging 效果好,但更容易 Overfit。
3、Blending:用不相交的数据训练不同的 Base Model,将它们的输出取(加权)平均。实现简单,但对训练数据利用少了。
4、Stacking
Stacking的基本思想是用一些基分类器进行分类,然后使用令一个分类器对结果进行整合。
用2-fold stacking作为例子:首先将训练数据分成A和B两份,再使用第一阶段模型用A训练,然后对B生成预测值,第三步通过同样的模型用B训练,生成A的预测值,第四是使用整个训练集来拟合这个模型,并生成测试集的预测值,最后像第二步一样训练第二阶段模型。
这里我们选取Bagging这个模型融合工具来对进行模型融合

from sklearn.ensemble import BaggingRegressor
def BaggingRegressor_predictions(data_train, data_test):
    ttnk_data_train_X = data_train.drop(['Survived'],axis=1)
    ttnk_data_train_Y = data_train['Survived']
    ttnk_data_test_X = data_test.drop(['Survived'],axis=1)
    clf = RandomForestRegressor(random_state=0)
    br_est =  BaggingRegressor(clf, n_estimators=20, max_samples=0.8, max_features=1.0, bootstrap=True, bootstrap_features=False, n_jobs=-1)
    br_est.fit(ttnk_data_train_X, ttnk_data_train_Y)
    predictions = br_est.predict(ttnk_data_test_X)
    result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
    result.to_csv("E:\\kaggle\\ttnk\\BaggingRegressor_predictions.csv", index=False)

生成提交文件于kaggle:
得分为0.77033
模型还有很大的改进空间,关于模型的改进我们可以从三方面来入手
(1)特征工程:对数据的进一步理解,通过各特征之间的联系来建立更好的特征
(2)关于模型的拟合问题,可以参考吴恩达老师深度学习的课程,对原始训练集进一步划分,来进行训练预测。对模型的欠拟合或者过拟合进行判断,再进行模型的调参
(3)关于模型融合可以选择stacking方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值