首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

机器学习入门案例分析-泰坦尼克号生存预测

泰坦尼克号生存预测是Kaggle举办的一项数据挖掘比赛,目的是根据给定的乘客信息来预测该乘客最终是否可以存活下来。泰坦尼克号生存预测是Kaggle竞赛的入门案例,同时也是机器学习的经典案例,今天我们用Python3结合机器学习库sklearn进行分析。欢迎关注微信公众号《Python练手项目实战》,后台回复"资源"即可免费获得python机器学习全套课程视频资源。

导入用到的库

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

from sklearn.linear_model import LogisticRegression

from sklearn.svm import SVC

from sklearn.ensemble import RandomForestClassifier,GradientBoostingClassifier,VotingClassifier

from xgboost import XGBClassifier

from sklearn.model_selection import cross_val_score

from sklearn.model_selection import StratifiedKFold

from sklearn.model_selection import GridSearchCV

加载和查看数据

在进行分析前的第一步就是要加载和查看我们的数据

trainData = pd.read_csv('train.csv')#加载训练数据

testData= pd.read_csv('test.csv')#加载测试数据

full_data = [trainData,testData]

trainData.info()#训练数据的信息

testData.info()

trainData.sample(n=10) #随机查看训练数据

testData.sample(n=10)

从输出的结果中可以看出:

1、训练集中一共有819个数据,其中Age, Cabin和Embarked列的数据有缺失值

2、测试集中一共有418个数据,其中Age, Fare, Cabin列的数据有缺失值

3、训练集中的特征一共有:PassengerId, Survived, Pclass, Name, Sex, Age, SibSp, Parch, Ticket, Fare, Cabin和Embarked; 其中Name , Sex, Ticket, Cabin和Embarked列数据为文本数据,这在后面需要进行编码的转换

4、而测试集中的数据基本和训练集中的一样,只不过少了Survived列,这也是我们要预测的那一列数据

描述性统计

一、生存率:

训练集中存活下来的人占比0.383

trainData["Survived"].value_counts(normalize=True)

0 0.616162

1 0.383838

二、分类变量和生存率

在给定的特征中,分类变量或离散型变量一共有:Pclass, Sex, SibSp, Parch, Embarked,用柱状图表示它们和生存率之间的关系

fig,axes = plt.subplots(2,3,sharey=True)

#Pclass和生存率

sns.factorplot(x='Pclass',y='Survived',data=trainData,kind='bar',ax=axes[0,0])

sns.barplot(x='Sex',y='Survived',data=trainData,ax=axes[0,1])

sns.barplot(x='SibSp',y='Survived',data=trainData,ax=axes[0,2])

sns.barplot(x='Parch',y='Survived',data=trainData,ax=axes[1,0])

sns.barplot(x='Embarked',y='Survived',data=trainData,ax=axes[1,1])

从上面的描述统计中可以看出:

1、不同阶级(Pclass)下用户之间的存活率差别比较大,而且Pclass=1的乘客的存活率最大

2、女性存活的几率远大于男性,说明性别对生存率的影响较强

3、SibSp和Parch对存活率也有一定的影响,而且他们的数值越小的话就越有可能存活下来

4、Embarked对生存率也有一定的影响,考虑保留在最终的特征中

三、连续变量和生存率

给定的特征中,连续变量有:Age和Fare, 他们和Survived的情况如下:

从上面的图中可以看出:

fig,axes = plt.subplots(2,1)

#不同Survived下年龄的分布

sns.kdeplot(trainData["Age"][(trainData["Survived"] == 0) & (trainData["Age"].notnull())], color="Red", shade = True,ax=axes[0],label='Not Survived')

sns.kdeplot(trainData["Age"][(trainData["Survived"] == 1) & (trainData["Age"].notnull())], color="Blue", shade= True,ax=axes[0],label='Survived')

#不同Survived下Fare的分布

sns.kdeplot(trainData["Fare"][(trainData["Survived"] == 0) & (trainData["Fare"].notnull())], color="Red", shade = True,ax=axes[1],label='Not Survived')

sns.kdeplot(trainData["Fare"][(trainData["Survived"] == 1) & (trainData["Fare"].notnull())], color="Blue", shade= True,ax=axes[1],label='Survived')

1、在年龄方面,大部分乘客的年龄都集中在20-40之间,而存活下来的乘客年龄有两个峰段,年龄较小(0-8)和年龄中等(20-35)

2、而Fare在存活的乘客和没有存活的乘客的分布较为相似,但没有存活的乘客的Fare更为集中一些

特征处理

一、特征处理的步骤

异常值处理(Correcting):检测数据中是否有异常值的出现,如果有的话,可以采取删除该实例或用其他数值来替换异常值。

缺失值处理(Completing):从之前的查看数据时,就发现数据中存在缺失值,对于这些缺失值,如果样本量很大的话,可以考虑删除;但是这里样本量比较小,考虑用其他的数值来代替这些缺失值。

创建特征(Creating):创建可能对预测结果有帮助的其他特征。

特征编码转化(Converting):主要是将文本类型的数据、分类变量转换为可供模型计算的数值型变量。

二、异常值处理(Correcting)

对于分类变量而言,通过前面的描述统计可以看出不存在异常的地方, 因此异常值检测主要就是集中于连续型变量(Age, Fare)上,用箱线图来检测:

fig,axes = plt.subplots(1,2)

sns.boxplot(y='Age',data=trainData,ax=axes[0])

sns.boxplot(y='Fare',data=trainData,ax=axes[1])

fig.show()

可以看出:相比于年龄,Fare列的数据更集中一点;

Age列数据有几个异常值,都是年龄比较大的乘客,不过这也比较正常;

Fare中有一个极端值是大于500的,可以考虑将其替换为Fare的中位数。

三、缺失值处理(Completing)

在训练集中缺失数据的列有:Age, Cabin 和Embarked;在测试集中有:Age, Fare, Cabin和Embarked。处理的方法如下:

Age:首先要从乘客的名称中提取出称谓(title), 然后将缺失的具有某个title的乘客的年龄替换为拥有这个title的其他乘客年龄的均值

Cabin:该列数据缺失太多了,因此考虑最终将其从特征中去掉

Embarked:用该列的中位数来替换缺失值

Fare:用中位数来替换缺失值

#如果title不在出现次数较多的title中,将其替换为Rare

def fix_title(title):

if title.strip() not in ['Mr','Miss','Mrs','Master','Dr']:

return 'Rare'

else:

return title.strip()

# 用含有相同title的人的年龄的均值来填补年龄的缺失值

for dataset in full_data:

#提取名称中的title

dataset['Title'] = dataset['Name'].str.extract(', (\S+). ',expand = False)

#将一些出现次数较少的title替换为Rare

dataset['Title'] = dataset['Title'].map(fix_title)

#替换年龄中的缺失值

dataset['Age']=dataset.groupby('Title')['Age'].apply(lambda x:x.fillna(x.mean()))

#用Embarked的众数来填补缺失值

dataset['Embarked'].fillna(dataset['Embarked'].mode()[0],inplace=True)

#测试数据中的Fare有缺失值,因此用中位数来替代

dataset['Fare']= dataset['Fare'].fillna(dataset['Fare'].median())

#查看训练集和测试集中的缺失值情况

trainData.isnull().sum()

testData.isnull().sum()

四、创建特征(Creating)

创建特征主要是从数据中提取出一些对预测结果有帮助的特征,我新建的特征有以下几个:

FamilySize:乘客家庭的大小,有SibSp和Parch相加,再加1得到

IsAlone:乘客是否是独自一人,当FamilySize==1时,IsAlone为True

IsMother:表明该乘客是否为母亲

Child:表示该乘客是否为孩子

def is_mother(row):

if row['Title']=='Mrs' and row['Age']>20 and row['Parch']>0:

return 1

else:

return 0

for dataset in full_data:

dataset['FamilySize'] = dataset['SibSp'] + dataset['Parch'] + 1

dataset['IsAlone'] = dataset.apply(lambda x:1 if x['FamilySize']==1 else 0,axis=1)

dataset['Mother'] = dataset.apply(is_mother,axis=1)

dataset['Child'] = dataset.apply(lambda row:1 if row['Age']

五、特征编码转化(Converting)

现在就剩下最后的编码转换部分了:

文本类型的列有:Sex, Embarked,Title, 对于这些列而言,需要将文本转换为对应的数字编码,便于模型的计算。

对于Age, Fare这样的数值列数据而言,他们的数据范围和其他列的数据范围相差太大,会导致模型受这两列的影响很大,因此也将其进行分组,然后转换为离散型的变量。

#将分类变量转换为数值型

sex_mapping ={'female':0,'male':1}

embarked_mapping = {'S':1,'C':2,'Q':3}

title_mapping = {'Mr':1,'Miss':2,'Mrs':3,'Master':4,'Dr':5,'Rare':6}

for dataset in full_data:

dataset['Sex'] = dataset['Sex'].map(sex_mapping)

#另外创建一个变量:Class_Sex

dataset['Class_Sex'] = dataset['Pclass'] * dataset['Sex']

dataset['Embarked'] = dataset['Embarked'].map(embarked_mapping)

dataset['Title'] = dataset['Title'].map(title_mapping)

#将Age和Fare分组并编码

def age_encode(age):

if age

elif age

elif age

elif age

elif age

def fare_encode(fare):

if fare

elif fare

elif fare

elif fare

for dataset in full_data:

dataset['Age'] = dataset.Age.map(age_encode)

dataset['Fare'] = dataset.Fare.map(fare_encode)

#最后去掉一些我们不需要的列

drop_columns=['PassengerId','Name','SibSp','Parch','Ticket','Cabin']

trainData.drop(drop_columns,axis =1,inplace=True)

testData.drop(drop_columns,axis=1,inplace=True)

训练单个模型

#准备训练的数据

X_train=trainData.iloc[:,1:]

y_train=trainData['Survived']

X_test = testData

#用于交叉验证

kf = KFold(n_splits = 10,random_state = 0)

分别使用5个基本的分类模型来拟合训练数据,并根据交叉验证的结果来选择模型的参数

#模型1:训练逻辑回归模型

C = [0.01,0.1,0.5,1,2,3,4,5,6]

accuracy = dict()

for c in C:

ls = LogisticRegression(penalty='l2',C = c, solver='lbfgs',random_state=0)

cross_scores = cross_val_score(ls,X_train,y=y_train,cv =kf)

accuracy[c] = np.mean(cross_scores)

print('best C:',sorted(accuracy.items(),key=lambda x:x[1],reverse=True)[0])

#模型2:用支持向量机来拟合模型

svc = SVC(random_state=0)

params={'kernel':['linear','rbf','sigmoid'],

'C':[1,1.2,1.4,1.5,1.8,2,2.5,3,4,10,20,50],

'gamma': [0.1,0.15,0.2,0.25,0.3,0.4]}

best_model_svc = GridSearchCV(svc,param_grid = params,refit=True,cv=kf).fit(X_train,y_train)

print('best accuracy',best_model_svc.best_score_

print('best parameters',best_model_svc.best_params_)

#模型3:用随机森林来拟合模型

params = {'n_estimators':[50,100,150,200,250],

'max_depth':[3,5,7],

'min_samples_leaf':[2,4,6]}

RF = RandomForestClassifier(random_state=0)

best_model_rf = GridSearchCV(RF,param_grid=params,refit=True,cv=kf).fit(X_train,y_train)

print('best accuracy',best_model_rf.best_score_)

print('best parameters',best_model_rf.best_params_)

#模型4:用GBDT来拟合模型

gbdt = GradientBoostingClassifier(random_state=0)

params ={'learning_rate':[0.01,0.05,0.1,0.15,0.2],

'n_estimators':[100,300,500],

'max_depth':[3,5,7]}

best_model_gbdt = GridSearchCV(gbdt,param_grid=params,refit=True).fit(X_train,y_train)

print('best accuracy',best_model_gbdt.best_score_)

print('best parameters',best_model_gbdt.best_params_)

#模型5:xgboost拟合模型

xbc = XGBClassifier(random_state = 0)

params ={'n_estimators':[50,100,300,500],

'max_depth':[2,3,5,7],

'learning_rate':[0.01, 0.03, 0.05, 0.1, 0.25]}

best_model_xbc = GridSearchCV(xbc,param_grid=params,refit=True,cv=kf).fit(X_train,y_train)

print('best accuracy',best_model_xbc.best_score_)

print('best parameters',best_model_xbc.best_params_)

模型运行的结果:

从单个模型的结果来看,随机森林交叉验证的准确率是最高的,为0.8350。分别用上面的模型来拟合训练集的数据,并对测试集进行预测,提交之后得到的准确率如下:

best C: (2, 0.82383270911360795)

best accuracy 0.83164983165

best parameters {'C': 1.2, 'gamma': 0.1, 'kernel': 'rbf'}

best accuracy 0.832772166105

best parameters {'max_depth': 5, 'min_samples_leaf': 2, 'n_estimators': 250}

best accuracy 0.830527497194

best parameters {'learning_rate': 0.01, 'max_depth': 3, 'n_estimators': 100}

best accuracy 0.83164983165

best parameters {'learning_rate': 0.01, 'max_depth': 2, 'n_estimators': 300}

LogisticRegression : 0.80382

SVC : 0.78947

RandomForest : 0.79425

GradientBoostingClassifier : 0.79904

XGBClassifier : 0.79425

看起来逻辑回归模型得到的准确率是最高的。

集成学习模型

为了让预测的结果准确率更高一点,可以将上面5个表现最佳的模型结合起来,采用多数表决(majority vote)的方式来对一个实例进行预测。

多数表决的具体方法:对于测试集中的一个实例而言,如果有超过3个模型预测的结果为1,那么最终的结果就是1,否则预测的结果为0。可以借助sklearn的VotingClassifier来实现。

models = [('lr':LogisticRegression(penalty='l2',C =2, solver='lbfgs',random_state=0)),

('svc':SVC(kernel='rbf',C=1.2,gamma=0.1,random_state=0)),

('rf':RandomForestClassifier(n_estimators=250,max_depth=5,min_samples_leaf=2,random_state=0)),

('gbdt':GradientBoostingClassifier(learning_rate=0.01,n_estimators=100,max_depth=3,random_state=0)),

('xgbc':XGBClassifier(learning_rate=0.01,max_depth=2,n_estimators=300,random_state=0))

vote= VotingClassifier(models,voting='hard')

vote.fit(X_train,y_train)

#最后利用vote对测试集中的数据进行预测

y_test_pred = vote.predict(X_test)

将测试集中的PassengerId和预测的结果y_test_pred输出为csv文件并提交到Kaggle上就可以得到预测的准确率:0.79425。

综上,通过对泰坦尼克号数据集进行数据描述、特征构建和拟合模型,最终发现利用逻辑回归模型可以得到最高的准确率(0.80382)。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180730A0JEUB00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券