机器学习入门实战 -- Titanic乘客生还预测
本文主要是对泰坦尼克号沉船事件进行预测:在当时的情况下,什么样的人更容易存活?
在Kaggle中泰坦尼克项目主界面的Data栏获取,有测试数据、训练数据和提交格式三个文件,本平台已在云端配置好相关数据,运行下面的代码块即可读取相应的数据集。
In [ ]:
#首先导入相关的python包
import pandas as pd
import numpy as np
import sklearn as sk
In [ ]:
#读取泰坦尼克数据集
import sys
sys.path.append('/home/ubuntu/MyFiles/PublicData/')
import os
import datasets_path
In [ ]:
#训练数据
train = pd.read_csv(datasets_path.titanic_train_dir)
#测试数据
test = pd.read_csv(datasets_path.titanic_test_dir)
print('训练集数量:',len(train), '测试集数量:',len(test))
In [ ]:
#合并两个数据集,对数据集进行数据清洗
Full = train.append(test)
print('合并后的数据集:',Full.shape)
在处理数据之前,我们先观察数据的形式对数据有一个大概的理解
In [ ]:
#查看数据的前5行
Full.head()
查看数据集的统计信息,查看是否有异常数据。
In [ ]:
#按列获取数据类型的描述统计信息,非数字类型数据不会被统计
Full.describe()
按列查看数据关于不同特征属性的数量,检查数据是否有缺失值
In [ ]:
#查看每一列的数据类型和数据总数
Full.info()
可以看到船舱号(Cabin)缺失的数据较多,接下来需要对相应的特征属性补全缺失值。在这个例子中,对于数值型数据,我们采用平均值填补;非数值型采用众数填补。
In [ ]:
#票价(Fare)为数值型数据,缺失一条可以采用均值补充
Full['Fare'] = Full['Fare'].fillna(Full['Fare'].mean())
In [ ]:
#年龄(Age)同理
Full['Age'] = Full['Age'].fillna(Full['Age'].mean())
In [ ]:
#Embarked为非数值型数据,采用众数填充
print('众数:',Full['Embarked'].mode())
Full['Embarked'] = Full['Embarked'].fillna('S')
In [ ]:
#Cabin为字符串变量,用U补充表示UnKnown
Full['Cabin'] = Full['Cabin'].fillna('U')
In [ ]:
#查看填充结果
Full['Embarked'].value_counts()
对于字符型特征属性,需要转换为数值类型替代通常使用One-hot编码,比如性别(Sex)
In [ ]:
#对于特征属性(Sex),男(male = 1);女(female = 0)。
Sex_dict = {'male':1, 'female':0}
#下面使用map函数对数据进行转换,map函数对Series的内个数据元素应用自定义的函数计算
Full['Sex'] = Full['Sex'].map(Sex_dict)
Full.head()
#One-hot编码是对操作2个类别以上的采集型编码,因为性别只有两个类别,所以不需要使用One-hot编码。
使用数据框的get_dummies( )方法可以实现One-hot编码。所以,重编码后新的特征,需要新建一个数据框存储下来:
Embarked的值分别为S,C,Q
In [ ]:
Full['Embarked'].head()
In [ ]:
embarkerDF = pd.DataFrame()
embarkerDF = pd.get_dummies(Full['Embarked'], prefix='Embarked')
embarkerDF.head()
添加One-hot编码产生的虚拟变量到数据集Full,并将原有的Embarked属性删除
In [ ]:
Full = pd.concat([Full, embarkerDF], axis=1)
#删除Embarked
Full.drop('Embarked', axis=1, inplace=True)
Full.head()
接下来处理特征属性Name
In [ ]:
#定义函数,从姓名中提取头衔
def getTitle(name):
Name = name.split(',')[1] #split按指定符号分割字符串
title = Name.split('.')[0]
Title = title.strip() #移除字符串首尾制定的字符默认为空格
return Title
In [ ]:
#同上,先新建一个数据框存放处理后的数据
titleDF = pd.DataFrame()
titleDF['Title'] = Full['Name'].map(getTitle)
titleDF['Title'].head(),Full['Name'].head()
In [ ]:
'''
数据集中的头衔有很多,为了简化我们将其映射为下面几种头衔类别,并对其One-hot处理
例如:Ms已婚男士,Mrs已婚女士,Officer政府官员,Royalty皇室成员,Miss年轻未婚女子,Master有技能的人员
'''
title_dict = {'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'}
titleDF['Title'] = titleDF['Title'].map(title_dict)
titleDF = pd.get_dummies(titleDF['Title'])
titleDF.head()
In [ ]:
#将titleDF添加到Full数据集并删除特征属性Name
Full = pd.concat([Full,titleDF], axis=1)
Full.drop('Name', axis=1, inplace=True)
Full.head()
In [ ]:
#家庭情况信息处理
familyDF = pd.DataFrame()
familyDF['family_size'] = Full['Parch'] + Full['SibSp'] + 1#家庭人数=同代亲属(Parch)+不同代亲属(SibSp)+乘客本身
familyDF['family_single'] = familyDF['family_size'].map(lambda s:1 if s==1 else 0)
familyDF['family_small'] = familyDF['family_size'].map(lambda s:1 if 2<=s<=4 else 0)
familyDF['family_large'] = familyDF['family_size'].map(lambda s:1 if s>4 else 0)
familyDF.head()
In [ ]:
Full = pd.concat([Full, familyDF], axis=1)
Full.head()
选取原则:根据所有变量的相关系数矩阵,筛选出与预测标签Survived最相关的特征变量。
In [ ]:
corrDF = Full.corr()
corrDF
这里选择‘Survived’列,按列降序排列,就能看到哪些特征最正相关,哪些特征最负相关,将其筛选出来作为模型的特征输入。
In [ ]:
#按相关系数降序排列
corrDF['Survived'].sort_values(ascending = False)
选择title_df, pclass_df, family_df, Fare, cabin_df, Sex作为特征。
构建整体数据集的特征数据框full_x(包含1309行整体数据集特征),再使用loc属性拆分出891行原始数据集特征source_x和标签source_y、481行测试数据集特征test_x:
In [ ]:
Full_X = pd.concat([titleDF,
Full['Pclass'],
familyDF,
Full['Fare'],
embarkerDF,
Full['Sex'],
Full['Age']], axis=1)
Full_X.head()
建模的时候,需要将原始数据集进行二八拆分:80%训练集+20%测试集。
训练集用于训练模型;测试集用于评估模型效果。
建模:
因为本例没有测试集的真实标记,所以从训练集中拆分出训练集和验证集以调整我们的模型。(可以上传模型提交到Kaggle验证自己模型的效果)
In [ ]:
#训练集特征属性
Row = 891
data_x = Full_X.loc[:Row-1,:]
#训练集标签
data_y = Full.loc[:Row-1, 'Survived']
predict_x = Full_X.iloc[Row:, :]
#loc会从0开始选取到指定的位置,所以Row需要减1
In [ ]:
data_x.shape,data_y.shape,predict_x.shape
依据8:2的比例划分训练集与验证集的数量
In [ ]:
from sklearn.cross_validation import train_test_split
#划分训练集与验证集
train_x, val_x, train_y, val_y = train_test_split(data_x,
data_y,
train_size=0.8)
这里我们选择较为简单的逻辑回归算法
In [ ]:
#导入算法
from sklearn.linear_model import LogisticRegression
#建立模型
model = LogisticRegression(C=1, max_iter=100)
In [ ]:
#训练模型
model.fit(train_x, train_y)
使用model.score方法,通过测试集得到模型预测准确率。
In [ ]:
model.score(val_x, val_y)
In [ ]:
pred_y = model.predict(predict_x)
pred_y = pred_y.astype(int)
passenger_id = Full.iloc[891:,4]
predDF = pd.DataFrame({'PassengerId':passenger_id,
'Survived':pred_y})
predDF.shape
predDF.head()
In [ ]:
predDF.to_csv('titanic_pred.csv', index=False)
易学智能云平台任一主机后可体验本案例的操作与交互式运行效果。传送门https://www.easyaiforum.cn/instanceList
更多学习案例请访问https://www.easyaiforum.cn/case