数据分析项目:Kaggle Titanic生存者预测

593 阅读4分钟

1.提出问题

根据已知人员数据信息,对其他人员的生存情况做出预测。

2.理解数据

1.数据来源:kaggle网站的Titanic生存模型预测,含有2组数据,训练集train.csv和测试集test.csv。
2.数据指标

passengerId:    
Survived: 是否生存,0=死亡,1=生存  
Pclass: 船票等级,1=一等舱,2=二等舱,3=三等舱
Name:姓名   
Sex:性别    
Age:年龄    
SibSp:船上的兄弟姐妹/配偶数  
Parch:船上的父母/子女数  
Ticket:船票号   
Fare:票价   
Cabin:船舱号  
Embarked:出发港口,C=瑟堡(法国),S=南安普顿 ,Q=昆士敦  

3.数据清洗

(1)如果数据集很多,只有很少的缺失值,可以删掉带缺失值的行;
(2)如果该属性相对学习来说不是很重要,可以对缺失值赋均值或者众数,比如Embarked。
(3)对于缺失很多的重要属性,可以赋值Uknow,比如船舱号Cabin。
导入模块:

import numpy as np
import pandas as pd

读取文件:(类型csv/text/DataFrame)

train = pd.read_csv('C:/Users/titanic/train.csv')
test = pd.read_csv('C:/Users/titanic/test.csv')

查看数据结构:

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

合并数据集,便于清洗:

# ignore_index=True产生新索引,sort=True对新数据调整
full = train.append(test, ignore_index=True, sort=True)
print('合并后的数据集:', full.shape)
#查看数据集结构发现缺失的指标有:Age/Cabin/Embarked/Fare/
print(full.info())

(1)数值型缺失——均值填充fillna

full['Age'] = full['Age'].fillna(full['Age'].mean())
full['Fare'] = full['Fare'].fillna(full['Fare'].mean())

(2)字符串型缺失——数量少填充最频繁的值,多则取新值uknow

print(full['Embarked'].head())
full['Embarked'] = full['Embarked'].fillna('S')

print(full['Cabin'].head())
full['Cabin'] = full['Cabin'].fillna('U')

(3)分类数据转换:数值或one-hot编码

# 性别Sex:female/male转换为数值0/1,map对指定列做映射
sex_mapDict = {'male': 1,'female': 0}
full['Sex']=full['Sex'].map(sex_mapDict)

# 登船港口Embarked:S/C/Q进行One-hot编码,用get_dummies
# 存放提取的特征
embarkedDf = pd.DataFrame()
# 转化为3个新变量,prefix列名加前缀
embarkedDf = pd.get_dummies(full['Embarked'], prefix='Embarked')
print(embarkedDf.head())
# 合并,axis=1表示列合并
full = pd.concat([full, embarkedDf], axis=1)
# 丢弃原来的Embarked列,inplace=1表示在原表修改,不创建新对象
full.drop('Embarked', axis=1, inplace=True)

# 船舱等级Pclass:进行One-hot编码
pclassDf = pd.DataFrame()
pclassDf = pd.get_dummies(full['Pclass'], prefix='Pclass')
print(pclassDf.head())
full = pd.concat([full, pclassDf], axis=1)
full.drop('Pclass', axis=1, inplace=True)

# 船舱号Cabin:编号进行One-hot编码
# lambda定义匿名函数,返回Cabin的首字母
cabinDf = pd.DataFrame()
full['Cabin'] = full['Cabin'].map(lambda c: c[0])
cabinDf = pd.get_dummies(full['Cabin'], prefix='Cabin')
print(cabinDf.head())
full = pd.concat([full, cabinDf], axis=1)
full.drop('Cabin', axis=1, inplace=True)
# 也可以full = pd.get_dummies(full,columns=['Cabin']),更简洁

# 从姓名(名,头衔.姓)中获取头衔姓名进行one-hot编码,可定义函数
def getTitle(name):
    str1 = name.split(',')[1]
    str2 = str1.split('.')[0]
    str3 = str2.strip()
    return str3
    
titleDf = pd.DataFrame()
titleDf['Title'] = full['Name'].map(getTitle)
# 查看某列有多少不同值
print(titleDf['Title'].value_counts())
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"
}
titleDf['Title']=titleDf['Title'].map(title_mapDict)
titleDf=pd.get_dummies(titleDf['Title'])
print(titleDf.head())
full=pd.concat([full,titleDf],axis=1)
full.drop('Name',axis=1,inplace=True)

# 划分家庭规模:小家庭=1,中等家庭(2,4),大家庭>=5,进行one-hot编码
familyDf=pd.DataFrame()
familyDf['FamilySize']=full['Parch']+full['SibSp']+1

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 s>=5 else 0)
print(familyDf.head())
full=pd.concat([full,familyDf],axis=1)

4.构建模型

生成相关系数矩阵,选择特征:

corrDf=full.corr()
print(corrDf)
print(corrDf['Survived'].sort_values(ascending=False))

full_x=pd.concat([titleDf,
                  pclassDf,
                  familyDf,
                  full['Fare'],
                  cabinDf,
                  embarkedDf,
                  full['Sex']]
                 ,axis=1)
print(full_x.head())

将train、test数据集分开:

sourceRow=891
#原始数据:特征
x=full_x.iloc[0:sourceRow,:]
print(x.shape)
#原始数据:标签
y=full.loc[0:sourceRow-1,'Survived']
print(y.shape)
#预测数据集:特征
pred_x=full_x.iloc[sourceRow:,:]
print('原始数据集有%s行'%source_x.shape[0])

#将原始数据分为训练数据和测试数据
from sklearn.model_selection import train_test_split
train_x,test_x,train_y,test_y=train_test_split(x,y,train_size=0.8)
#输出数据集大小
print('原始数据集特征:',x.shape,
      '训练数据集特征:',train_x.shape,
      '测试数据集特征:',test_x.shape)
print('原始数据集特征:',y.shape,
      '训练数据集特征:',train_y.shape,
      '测试数据集特征:',test_y.shape)

#使用逻辑回归进行预测,max_iter默认1000,警告时可以调大
from sklearn.linear_model import LogisticRegression
model=LogisticRegression(max_iter=5000)
model.fit(train_x,train_y)

5.模型评估

#模型评价:评分(即准确率0.8379)
print(model.score(test_x,test_y))

6.实施方案

补充:交叉验证思想
把某种意义下将原始数据(dataset)进行分组,一部分作为训练集(train set),另一部分作为验证集(test set),首先用训练集对分类器进行训练,再利用验证集来测试训练得到模型(model),以此来作为评价分类器的性能指标。
交叉验证用于评估模型的预测性能,尤其是训练好的模型在新数据上的表现,可以在一定程序熵减少过拟合。
交叉验证还可以从有限的数据中获取尽可能多的有效信息。