机器学习入门之泰坦尼克号预测存活情况(Taggle)

前言:

本文中的项目是Taggle的入门比赛项目,旨在让大家对Taggle的比赛有一个大致的了解和一些基本的操作。在参考了一些资料进行整理的情况下,总结出了这篇入门教学案例。
本文就是就一个机器学习的整个过程进行了大致分析,帮助大家对机器学习有一个实践上的认识。最后,因为是入门案例,所有最后的正确率并没有太高—75%左右,在Taggle排在倒数,给我一点时间,后面会更新百分比正确率的方法。
所需数据和代码:提取码:iiyk

项目背景:
泰坦尼克号的沉没是历史上最臭名昭著的沉船之一。
1912年4月15日,人们普遍认为“永不沉没”的皇家邮轮“泰坦尼克”号在处女航中撞上冰山后沉没。不幸的是,船上没有足够的救生艇供所有人使用,导致2224名乘客和船员中有1502人死亡。
虽然生存中有一些运气因素,但似乎有些人比其他人更有可能生存下来。
在这个挑战中,我们要求你建立一个预测模型来回答这个问题:“什么样的人更适合存活下来?

介绍:

机器学习三层架构:

image-20210808111612379

机器学习的本质:机器取代人直接做决策

云计算:用低成本存储和计算海量数据

机器学习算法:人类思考决策的过程抽象成数学模型,用数学的方法给这个模型找到最优化的解,然后把这个解转换成代码命令,让机器可以去执行,完成机器大脑的构建。模型靠海量数据不断学习来优化自己的决策。

机器学习的步骤:

image-20210808113703481

过程:

提出问题:

什么人在泰坦尼克号上更适合生存?

泰坦尼克号的沉没是历史上最臭名昭著的沉船之一。

1912年4月15日,人们普遍认为“永不沉没”的皇家邮轮“泰坦尼克”号在处女航中撞上冰山后沉没。不幸的是,船上没有足够的救生艇供所有人使用,导致2224名乘客和船员中有1502人死亡。

虽然生存中有一些运气因素,但似乎有些人比其他人更有可能生存下来。

在这个挑战中,我们要求你建立一个预测模型来回答这个问题:“什么样的人更容易存活下来。使用乘客数据(如姓名、年龄、性别、社会经济阶层等)。

理解数据:

1、导入查看数据所需要的包

import numpy as np
import pandas as pd

2、导入数据文件

#训练数据集
train = pd.read_csv('./train.csv')
#测试数据集
test = pd.read_csv('./test.csv')

注:数据文件可以在这个地址下载 百度网盘 提取码:62jt

3、查看数据结构

print('训练数据集:',train.shape,'测试数据集:',test.shape)

image-20210808185004653

训练数据集有891行,12列;测试数据集有418行,11列;

测试数据集比训练数据集少了存活(Survived)这一列一列

4、合并数据

#合并数据集,方便同时对两个数据集进行清洗
full = train.append(test,True)
print('合并后的数据:',full.shape)

image-20210808185326592

5、查看数据

用head()函数,可以返回前5行的数据

#查看数据
full.head()
#Passengerld:顾客编号
#Survived:1:存活,0:死亡
#Plcass:一等舱,二等舱,三等舱
#name:姓名
#Sex: 性别
#Age:年龄
#SibSP:船上同代亲属数
#Parch:船上不同代亲属数
#Ticket:船票编号
#Fare:船票价格
#Cabin:客舱号
#Embarked:登船港口 S:Southampton英国南安普顿 C:Cherbourg法国 瑟堡市 Q:Queenstowm爱尔兰 昆士敦

image-20210808185413758

6、获得数据描述信息

describe()函数只能返回数字数据类型,不能查看字符串数据类型

#获取数据类型列的描述统计信息
full.describe()
#count数据总数
#mean平均值
#std标准值
#min最小值
#25%下四份位数
#50%中位数
#75%上四分位数
#max最大值

image-20210808185606573

其实在这里就可以看出问题,Fare的最小值为0。船票的价钱是不可能为0的,所以我们要注意数据的正确性。

7、查看每一列数据类型

#查看每一列的数据类型和数据总数
full.info()

image-20210808185943432

在这里我们注意到,Survived、Age、Fare、Cabin、Embarked都存在数据缺失现象。
我们发现数据总共有1309行。
其中数据类型列:年龄(Age)、船票价格(Fare)里面有缺失数据:
1)年龄(Age)里面数据总数是1046条,缺失了1309-1046=263,缺失率263/1309=20%
2)船票价格(Fare)里面数据总数是1308条,缺失了1条数据

字符串列:
1)登船港口(Embarked)里面数据总数是1307,只缺失了2条数据,缺失比较少
2)船舱号(Cabin)里面数据总数是295,缺失了1309-295=1014,缺失率=1014/1309=77.5%,缺失比较大
这为我们下一步数据清洗指明了方向,只有知道哪些数据缺失数据,我们才能有针对性的处理。所以接下来我们要进行数据清洗。

数据清洗:

1、数据预处理

image-20210808190428928

在这个案例中,我们只需要进行第三步缺失数据处理和异常值进行处理

缺失值进行处理

机器学习算法为了训练模型,要求所传入的特征中不能有空值。

  1. 如果是数值类型,用平均值取代
  2. 如果是分类数据,用最常见的类别取代
  3. 使用模型预测缺失值,例如:K-NN
#Age,Fare
#对于缺失数字数据类型处理,使用平均值进行填充
print('处理前:')
full.info()
#年龄(Age)
full['Age']=full['Age'].fillna( full['Age'].mean() )
#船票价格(Fare)
full['Fare'] = full['Fare'].fillna( full['Fare'].mean() )
print('处理红后:')
full.info()

image-20210808191851162

'''
Embarked
字符串数据,用最常见的类别取代
Embarked里的字符串类型:缺失较少
出发地点:S=英国南安普顿Southampton
途径地点1:C=法国 瑟堡市Cherbourg
途径地点2:Q=爱尔兰 昆士敦Queenstown
'''
full['Embarked'].value_counts()

image-20210808202712612

S是最多次出现的字符串类型

'''
从结果来看,S类别最常见。我们将缺失值填充为最频繁出现的值:
S=英国南安普顿Southampton
'''
full['Embarked'] = full['Embarked'].fillna( 'S' )

查看Cabin

#船舱号(Cabin):查看数据
full['Cabin'].head()

image-20210808203242616

船舱号(Cabin)里面数据总数是295,缺失了1309-295=1014,缺失率=1014/1309=77.5%,缺失比较大。如果用最常见的数据代替,那不具有代表性,所以用未知(UKnow)代替

#缺失数据比较多,船舱号(Cabin)缺失值填充为U,表示未知(Uknow) 
full['Cabin'] = full['Cabin'].fillna( 'U' )

查看最终缺失值处理情况,记住生成情况(Survived)这里一列是我们的标签,用来做机器学习预测的,不需要处理这一列

#查看最终情况
full.info()

image-20210808204444592

2、 特征提取

建议学之前,阅读我的这一篇博客机器学习之特征工程进行一个大致的了解。

介绍

坊间常说:“数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”。由此可见,特征工程在机器学习中占有相当重要的地位。在实际应用当中,可以说特征工程是机器学习成功的关键。

数据分类

查看数据类型,分为3种数据类型。并对类别数据处理:用数值代替类别,并进行One-hot编码,放入矩阵当中

将特征抽象成数据,方便代码实现

1.数值类型:
乘客编号(PassengerId),年龄(Age),船票价格(Fare),同代直系亲属人数(SibSp),不同代直系亲属人数(Parch)
2.时间序列:无
3.分类数据:
1)有直接类别的
乘客性别(Sex):男性male,女性female
登船港口(Embarked):出发地点S=英国南安普顿Southampton,途径地点1:C=法国 瑟堡市Cherbourg,出发地点2:Q=爱尔兰 昆士敦Queenstown
客舱等级(Pclass):1=1等舱,2=2等舱,3=3等舱
2)字符串类型:可能从这里面提取出特征来,也归到分类数据中
乘客姓名(Name)
客舱号(Cabin)
船票编号(Ticket)

分类数据:有直接类别的

  1. 乘客性别(Sex): 男性male,女性female
  2. 登船港口(Embarked):出发地点S=英国南安普顿Southampton,途径地点1:C=法国 瑟堡市Cherbourg,出发地点2:Q=爱尔兰 昆士敦Queenstown
  3. 客舱等级(Pclass):1=1等舱,2=2等舱,3=3等舱
性别(Sex)
'''
将性别的值映射为数值
男(male)对应数值1,女(female)对应数值0
'''
sex_mapDict={
    
    'male':1, 'female':0}
#map函数:对Series每个数据应用自定义的函数计算
full['Sex']=full['Sex'].map(sex_mapDict)
full.head()

image-20210808205947119

登船港口(Embarked)

登船港口就只要三个点:C,Q,S,而一个顾客对应这三个点中的一个,所以我们拆分成三个登船港口点:Embarked_C,Embarked_Q,Embarked_S。转换成数据模型就是[1,0,0],[0,1,0],[0,0,1]。这也叫做one-hot编码。

#存放提取后的特征
embarkedDf = pd.DataFrame()
'''
使用get_dummies进行one-hot编码,产生虚拟变量(dummy variables),列名前缀是Embarked
'''
embarkedDf = pd.get_dummies( full['Embarked'] , prefix='Embarked' )
#查看前5个
embarkedDf.head()

image-20210809113115689

#将Embarked替换成EmbarkedDF
#删除Embarked
full.drop('Embarked',axis=1,inplace=True)
#替换
full = pd.concat([full,embarkedDf],axis=1)
#展示
full.head()

image-20210809112152706

客舱等级(Pclass)

同登船港口一样,客舱等级分为1,2,3三个等级,进行拆分Pclass_1,Pclass_2,Pclass_3,数据模型也为[1,0,0],[0,1,0],[0,0,1]。

#Embarked,分为Pclass_1,Pclass_2,Pclass_3
pclassDf = pd.DataFrame()
#使用get_dummies进行one-hot编码,列名前缀是Pclass
pclassDf = pd.get_dummies( full['Pclass'] , prefix='Pclass' )
pclassDf.head()

image-20210809112949856

#添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full
full = pd.concat([full,pclassDf],axis=1)

#删掉客舱等级(Pclass)这一列
full.drop('Pclass',axis=1,inplace=True)
full.head()

image-20210809113222798

分类数据:字符串类型

字符串类型:可能从这里面提取出特征来,也归到分类数据中,这里数据有:

  1. 乘客姓名(Name)
  2. 客舱号(Cabin)
  3. 船票编号(Ticket)
姓名(Name)
#查看姓名
full[ 'Name' ].head()

image-20210809150614104

注意到在乘客名字(Name)中,有一个非常显著的特点:
乘客头衔每个名字当中都包含了具体的称谓或者说是头衔,将这部分信息提取出来后可以作为非常有用一个新变量,可以帮助我们进行预测。

我们看到姓名中’Braund, Mr. Owen Harris’,逗号前面的是“名”,逗号后面是‘头衔. 姓’

'''
定义函数:从姓名中获取头衔
'''
def getTitle(name):
    str1=name.split( ',' )[1] #Mr. Owen Harris
    str2=str1.split( '.' )[0]#Mr
    #strip() 方法用于移除字符串头尾指定的字符(默认为空格)
    str3=str2.strip()
    return str3
#存放提取后的特征
titleDf = pd.DataFrame()
#map函数:对Series每个数据应用自定义的函数计算
titleDf['Title'] = full['Name'].map(getTitle)
#查看titleDF的种类
titleDf.value_counts()

image-20210809152016409

我们现在已经知道了所有的头衔,一共18个。这太多了,进行进一步的简化。

定义以下几种头衔类别:

分类
Mr已婚男士
Mrs已婚妇女
Royalty王室(皇室)
Miss年轻未婚女子
Master有技能的人/教师
Officer政府官员
头衔 对应
Capt Officer
Col Officer
Major Officer
Jonkheer Royalty
Don Royalty
Sir Royalty
Dr Officer
Rev Officer
the Countess Royalty
Dona Royalty
Mme Mrs
Mlle Miss
Ms Mrs
Mr Mr
Mrs Mrs
Miss Miss
Master Master
Lady Royalty

基于以上的对应关系,用代码表示,并且用one-hot进行编码

#姓名中头衔字符串与定义头衔类别的对应关系
title_mapDict = {
    
    
                    "Capt":       "Officer",
                    "Col":        "Officer",
                    "Major":      "Officer",
                    "Jonkheer":   "Royalty",
                    "Don":        "Royalty",
                    "Sir" :       "Royalty",
                    "Dr":         "Officer",
                    "Rev":        "Officer",
                    "the Countess":"Royalty",
                    "Dona":       "Royalty",
                    "Mme":        "Mrs",
                    "Mlle":       "Miss",
                    "Ms":         "Mrs",
                    "Mr" :        "Mr",
                    "Mrs" :       "Mrs",
                    "Miss" :      "Miss",
                    "Master" :    "Master",
                    "Lady" :      "Royalty"
                    }

#map函数:对Series每个数据应用自定义的函数计算
titleDf['Title'] = titleDf['Title'].map(title_mapDict)

#使用get_dummies进行one-hot编码
titleDf = pd.get_dummies(titleDf['Title'])
#查看
titleDf.head()

image-20210809153145853

再替换到full总表当中,同样是先删除再替换。

#删掉姓名这一列
full.drop('Name',axis=1,inplace=True)
#添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full
full = pd.concat([full,titleDf],axis=1)
#查看
full.head()

image-20210809153413438

客舱号(Cabin)

查看客舱号

#查看客舱号的内容
full['Cabin'].head()

image-20210809154435785

我们用客舱号的首字母来代替客舱号的类别

#存放客舱号信息
cabinDf = pd.DataFrame()
#取首字母
full[ 'Cabin' ] = full[ 'Cabin' ].map( lambda c : c[0] )
##使用get_dummies进行one-hot编码,列名前缀是Cabin
cabinDf = pd.get_dummies( full['Cabin'] , prefix = 'Cabin' )

再替换到full总表当中,同样是先删除再替换。

#删掉客舱号这一列
full.drop('Cabin',axis=1,inplace=True)
#添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full
full = pd.concat([full,cabinDf],axis=1)
#查看
full.head()

image-20210809163143299

建立家庭人数和家庭类别(Family)

家庭人数=同代直系亲属数(Parch)+不同代直系亲属数(SibSp)+乘客自己

家庭类别:
小家庭Family_Single:家庭人数=1
中等家庭Family_Small: 2<=家庭人数<=4
大家庭Family_Large: 家庭人数>=5

#存放家庭信息
familyDf = pd.DataFrame()
#家庭人数
familyDf[ 'FamilySize' ] = full[ 'Parch' ] + full[ 'SibSp' ] + 1
#家庭类别
#if 条件为真的时候返回if前面内容,否则返回0
familyDf[ 'Family_Single' ] = familyDf[ 'FamilySize' ].map( lambda s : 1 if s == 1 else 0 )
familyDf[ 'Family_Small' ]  = familyDf[ 'FamilySize' ].map( lambda s : 1 if 2 <= s <= 4 else 0 )
familyDf[ 'Family_Large' ]  = familyDf[ 'FamilySize' ].map( lambda s : 1 if 5 <= s else 0 )

查看结果:

familyDf.head()

image-20210809163807396

添加到full总表中

#添加one-hot编码产生的虚拟变量(dummy variables)到泰坦尼克号数据集full
full = pd.concat([full,familyDf],axis=1)

查看结果:

full.head()

image-20210809164028762

结果:

到现在为止,所有的特征就已经提取完毕了。

查看最后结构

#查看总表结构
full.shape

image-20210809164258027

也就是说明现在有1309行数据,每行数据由33个特征值

3、特征选择

数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已

'''
DataFrame.corr(method='pearson', min_periods=1)
参数说明:
method:可选值为{‘pearson’, ‘kendall’, ‘spearman’}
pearson:Pearson相关系数来衡量两个数据集合是否在一条线上面,即针对线性数据的相关系数计算,针对非线性数据便会有误差。
kendall:用于反映分类变量相关性的指标,即针对无序序列的相关系数,非正太分布的数据
spearman:非线性的,非正太分析的数据的相关系数
min_periods:样本最少的数据量
返回值:各类型之间的相关系数DataFrame表格。
'''
corrDf = full.corr() 
#查看pearson相关系数
corrDf

image-20210811153235277

'''
查看各个特征与生成情况(Survived)的相关系数,
ascending=False表示按降序排列
'''
corrDf['Survived'].sort_values(ascending =False)

image-20210811153818777

根据各个特征与生成情况(Survived)的相关系数大小,我们选择了这几个特征作为模型的输入:

头衔(前面所在的数据集titleDf)、客舱等级(pclassDf)、家庭大小(familyDf)、船票价格(Fare)、船舱号(cabinDf)、登船港口(embarkedDf)、性别(Sex)

构建模型

用训练数据和某个机器学习算法得到机器学习模型,用测试数据评估模型

1、建立训练数据集和测试数据集

1)泰坦尼克号测试数据集因为是我们最后要提交给Kaggle的,里面没有生存情况的值,所以不能用于评估模型。
我们将Kaggle泰坦尼克号项目给我们的测试数据,叫做预测数据集(记为pred,也就是预测英文单词predict的缩写)。
也就是我们使用机器学习模型来对其生存情况就那些预测。
2)我们使用Kaggle泰坦尼克号项目给的训练数据集,做为我们的原始数据集(记为source),
从这个原始数据集中拆分出训练数据集(记为train:用于模型训练)和测试数据集(记为test:用于模型评估)。

sourceRow是我们在最开始合并数据前知道的,原始数据集有总共有891条数据
从特征集合full_X中提取原始数据集提取前891行数据时,我们要减去1,因为行号是从0开始的。

loc函数,loc指的是location。参数指的是索引,也就是[行,列]

#原始数据集有891行
sourceRow=891
#原始数据集:特征
source_X = full_X.loc[0:sourceRow-1]
#原始数据集:标签
source_y = full.loc[0:sourceRow-1,'Survived']
#预测数据集:特征
pred_X = full_X.loc[sourceRow:,:]

确保这里原始数据集取的是前891行的数据,不然后面模型会有错误

#原始数据集有多少行
print('原始数据集有多少行:',source_X.shape[0])
#预测数据集大小
print('预测数据集有多少行:',pred_X.shape[0])

image-20210811211820404

从原始数据集(source)中拆分出训练数据集(用于模型训练train),测试数据集(用于模型评估test)
train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和test data
train_data:所要划分的样本特征集
train_target:所要划分的样本结果
test_size:样本占比,如果是整数的话就是样本的数量

from sklearn.cross_validation import train_test_split 

#建立模型用的训练数据集和测试数据集
train_X, test_X, train_y, test_y = train_test_split(source_X ,
                                                    source_y,
                                                    train_size=.8)

#输出数据集大小
print ('原始数据集特征:',source_X.shape, 
       '训练数据集特征:',train_X.shape ,
      '测试数据集特征:',test_X.shape)

print ('原始数据集标签:',source_y.shape, 
       '训练数据集标签:',train_y.shape ,
      '测试数据集标签:',test_y.shape)

image-20210811211941709

查看数据

#原始数据查看
source_y

image-20210811213640268

2、 选择机器学习算法

这里使用逻辑回归(logisic regression)

#第1步:导入算法
from sklearn.linear_model import LogisticRegression
#第2步:创建模型:逻辑回归(logisic regression)
model = LogisticRegression()

3、训练模型

#第3步:训练模型
model.fit( train_X , train_y )

评估模型

# 分类问题,score得到的是模型的正确率
model.score(test_X , test_y )

image-20210811220102780

方案实施

得到预测结果上传到Kaggle

使用预测数据集到底预测结果,并保存到csv文件中,上传到Kaggle中,就可以看到排名。

#使用机器学习模型,对预测数据集中的生存情况进行预测
pred_Y = model.predict(pred_X)

'''
生成的预测值是浮点数(0.0,1,0)
但是Kaggle要求提交的结果是整型(0,1)
所以要对数据类型进行转换
'''
pred_Y=pred_Y.astype(int)
#乘客id
passenger_id = full.loc[sourceRow:,'PassengerId']
#数据框:乘客id,预测生存情况的值
predDf = pd.DataFrame( 
    {
    
     'PassengerId': passenger_id , 
     'Survived': pred_Y } )
predDf.shape
predDf.head()
#保存结果
predDf.to_csv( 'titanic_pred.csv' , index = False )

3、训练模型

#第3步:训练模型
model.fit( train_X , train_y )

评估模型

# 分类问题,score得到的是模型的正确率
model.score(test_X , test_y )

[外链图片转存中…(img-PYohazeb-1628692759422)]

方案实施

得到预测结果上传到Kaggle

使用预测数据集到底预测结果,并保存到csv文件中,上传到Kaggle中,就可以看到排名。

#使用机器学习模型,对预测数据集中的生存情况进行预测
pred_Y = model.predict(pred_X)

'''
生成的预测值是浮点数(0.0,1,0)
但是Kaggle要求提交的结果是整型(0,1)
所以要对数据类型进行转换
'''
pred_Y=pred_Y.astype(int)
#乘客id
passenger_id = full.loc[sourceRow:,'PassengerId']
#数据框:乘客id,预测生存情况的值
predDf = pd.DataFrame( 
    {
    
     'PassengerId': passenger_id , 
     'Survived': pred_Y } )
predDf.shape
predDf.head()
#保存结果
predDf.to_csv( 'titanic_pred.csv' , index = False )

猜你喜欢

转载自blog.csdn.net/fayoung3568/article/details/119618997