# coding: utf-8
# 本文预测泰坦尼克号生还率,鉴于前边学习了简单线性回归,逻辑回归,本案例对这两种方法进行运用
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 提纲思路:
# 第一步:导入数据,查看数据内容
# 第二步:数据清洗
# 1.数据预处理
# 2.数据特征提取
# 第三步:建立模型
# 第四步:模型评估
# 第五步:方案实施
# 1.提交到kaggle
# 2.撰写分析报告
# 忽略警告提示
import warnings
warnings.filterwarnings('ignore')
# 第一步:
# 导入数据,查看数据内容
# 这里的训练数据集和测试数据集已经分割好了,直接导入
trainDF = pd.read_csv('../机器学习(入门)/3.泰坦尼克号/train.csv')
testDF = pd.read_csv('../机器学习(入门)/3.泰坦尼克号/test.csv')
print(trainDF.shape,testDF.shape)
trainDF.head()
testDF.head()
# 记录下原始数据量
rowNum_train = trainDF.shape[0]
rowNum_test = testDF.shape[0]
print('训练数据量为:',rowNum_train)
print('测试数据量为:',rowNum_test)
# 合并数据集,方便对两个数据集同时清洗(此处合并除了少了一部分清洗工作,还有什么别的功能?)
integDF = pd.concat([trainDF,testDF],axis = 0,ignore_index = True)
integDF.shape
integDF.head()
# 查看数据描述信息
integDF.describe()
# 为了查看每一列的数据状态,我们用info方法
integDF.info()
# 信息解释:(共有1309条数据)
# 1.年龄:1046条非空数据,也就是有263条缺失数据,缺失占比:20.09%
# 2.舱位:295条非空数据,缺失较多,缺失占比:77.46%
# 3.登船入口:2条缺失
# 4.船票价格:1条缺失
# 5.生还数据:891条非空数据,缺失418条数据,缺失占比:31.93%
# 6.其他数据:完整
# 第二步(1):
# 对数据的预处理
# 对于缺失数据的处理,是一个很重要的问题,由于个人能力所限,仅用最简单的填充方法
# 对于数值类型的数据,用平均值来填充
integDF['Age'] = integDF['Age'].fillna(integDF['Age'].mean())
integDF['Fare'] = integDF['Fare'].fillna(integDF['Fare'].mean())
integDF.info()
# 对于登船入口的填充,这里用最简单(事实上也是不太靠谱)的方法:填充出现频次最高的信息
# 但是由于只有两条缺失,影响也不是很大
integDF['Embarked'].value_counts()
# s的出现频次最高,我们用s填充
integDF['Embarked'] = integDF['Embarked'].fillna('S')
integDF.head()
# 对于Cabin舱位的缺失值,用‘未知’来代替,‘U'
integDF['Cabin'] = integDF['Cabin'].fillna('U')
integDF.head()
# 检查清洗完毕的数据,除去标签数据’Survived‘需要预测,特征数据全部整理完毕
integDF.info()
# 第二步(2):
# 特征提取
'''
首先对特征数据进行分类,由以上信息可见有:
1.数值型信息(计量型):Age,Fare(船票价格),PassengerId,Parch(不同代直系亲属人数),SibSp(同代直系亲属人数)
2.时间序列:无
3.分类型信息:
1)直接分类信息:
乘客性别(Sex):男性male,女性female
登船港口(Embarked):S,Q,C
客舱等级(Pclass):1=1等舱,2=2等舱,3=3等舱
2)无固定分类,待提取分类:
乘客姓名(Name)
客舱号(Cabin)
船票编号(Ticket)
'''
# 对直接类别分类,用数字代替字符串
# 对于Age特征,两变量分类直接用01代替
sex_map={'male':1,'female':0}
integDF['Sex'] = integDF['Sex'].map(sex_map)
integDF.head()
# 对于Embarked登船港口,有三个变量:S,C,Q
# 对此可以采用生成虚拟变量的方式,即分为三类,是:1,否:0
EmbarkedDF = pd.get_dummies(integDF['Embarked'],prefix='Embarked')
EmbarkedDF.head()
# 以上方法叫做独热编码one_hot encoding,对于一个特征,如果有n个可能值,独热处理后则会变成n个二元特征
# 分类之后,我们需要将新的特征插入,删除旧特征
integDF = pd.concat([integDF,EmbarkedDF],axis=1)
integDF.drop(labels='Embarked',axis=1,inplace=True)
integDF.shape
# 对于客舱等级,同样采取独热处理的方法,因为虽然是数字,还是不能清晰分类
PclassDF = pd.get_dummies(integDF['Pclass'],prefix='Pclass')
PclassDF.head()
# 联结新特征,抛掉旧特征
integDF = pd.concat([integDF,PclassDF],axis=1)
integDF.drop(labels='Pclass',axis=1,inplace=True)
integDF.shape
integDF.head()
# 接下来要对无固定分类的数据进行提取有效信息
# 乘客姓名(Name)
# 客舱号(Cabin)
# 船票编号(Ticket)
# 先对名字下手,查看一下名字有什么特征
[name for name in integDF['Name'].head(15)]
# 可以看到名字列中有头衔,Mr,Miss,Mrs,Master 等等,我们可以正则匹配出此头衔,然后加入新列表作为特征值
import re
L = []
pat = r',\s+(.+)\.'
for name in integDF['Name']:
d = re.findall(pat,name)
try:
L.append(d[0])
except:
print(name)
continue
print(L[:15])
# 将提取出的称谓加入数据框
TitleDF = pd.DataFrame(L,columns=['Title'])
len(TitleDF)
# 查看称谓数量
TitleDF['Title'].value_counts()
'''
在kaggle项目内容介绍中查看头衔类别:
Officer政府官员
Royalty王室(皇室)
Mr已婚男士
Mrs已婚妇女
Miss年轻未婚女子
Master有技能的人/教师
'''
#姓名中头衔字符串与定义头衔类别的映射关系
title_map = {
"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_map)
TitleDF.head()
# 使用独热编码方式分类
TitleDF = pd.get_dummies(TitleDF['Title'],prefix='Title')
TitleDF.head()
# 将新产生的特征数据框插入原数据框
integDF = pd.concat([integDF,TitleDF],axis=1)
integDF.drop(labels='Name',axis=1,inplace=True)
integDF.head()
# 接下来从客舱号中提取客舱类别
# 查看客舱名称规律
integDF['Cabin'].value_counts()
# 决定用首字母来区分客舱类别,由于是字符串类型,可以切片
CabinDF = pd.DataFrame()
CabinDF['Cabin'] = integDF['Cabin'].map(lambda a : a[0])
CabinDF['Cabin'].value_counts()
# one-hot 独热编码处理
CabinDF = pd.get_dummies(CabinDF['Cabin'],prefix='Cabin')
CabinDF.head()
# 将处理好的舱位数据加入原数据框
integDF = pd.concat([integDF,CabinDF],axis=1)
# 删除原有仓位信息
integDF.drop(labels=['Cabin'],axis=1,inplace=True)
integDF.head()
# 接下来要处理的是每个人家庭人数问题,有Parch(不同代直系亲属人数),SibSp(同代直系亲属人数)
# 此步骤的目的是将特征按照家庭人数分割,家庭人数包括了直系和非直系
familyList = []
for i in range(len(integDF)):
s = integDF['Parch'][i] + integDF['SibSp'][i] + 1
familyList.append(s)
familyList[:15]
familyDF = pd.DataFrame(familyList,columns=['num'])
familyDF.head()
# 此步骤按照家庭人数分类:1,2~5,5以上
familyDF['family_single'] = familyDF['num'].map(lambda a : 1 if a==1 else 0)
familyDF['family_small'] = familyDF['num'].map(lambda a : 1 if 15 else 0)
familyDF.head()
# 删除num,并加入原有数据框
familyDF.drop(labels=['num'],axis=1,inplace=True)
integDF = pd.concat([integDF,familyDF],axis=1)
integDF.drop(labels=['Parch','SibSp'],axis=1,inplace=True)
integDF.head()
integDF.info()
# 到此为止,数据整理完毕
# 第二步(3):
# 数据特征提取
#
# 建立相关性矩阵
corrDF = integDF.corr()
corrDF
# 查看各个特征与标签之间的相关性系数
orderList=corrDF['Survived'].sort_values(ascending=False)
orderList
# 根据相关性大小,选择一些相关系数绝对值较大的特征进行模型的输入:
# 头衔(前面所在的数据集TitleDF)、客舱等级(PclassDF)、家庭大小(familyDF)、
# 船票价格(Fare)、船舱号(CabinDF)、登船港口(EmbarkedDF)、性别(Sex)
X_integer = pd.concat([TitleDF,PclassDF,familyDF,CabinDF,EmbarkedDF,integDF['Fare'],integDF['Sex']],axis=1)
X_integer.head()
X_integer.info()
# 第三步:
# 建立模型
#
# 数据处理完成后,需要将原始数据和测试数据分离开来,前边并没有做过排序,因此顺序没有改变,直接取前891行就是原始数据
# 原始数据
source_X = X_integer.iloc[:891,:]
pred_X = X_integer.iloc[891:,:]
# 此处要注意,ix切片时属于闭区间切片
source_y = integDF.ix[:890,'Survived']
source_X.shape
source_y.shape
pred_X.shape
# 选取完数据,下面进行建模分析
from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test = train_test_split(source_X,source_y,test_size=0.2)
#输出数据集大小
print ('原始数据集特征:',source_X.shape,
'训练数据集特征:',X_train.shape ,
'测试数据集特征:',X_test.shape)
print ('原始数据集标签:',source_y.shape,
'训练数据集标签:',y_train.shape ,
'测试数据集标签:',y_test.shape)
# 建立模型,逻辑回归
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train,y_train)
model.score(X_test,y_test)
X_integer.info()
pred_y = model.predict(pred_X)
type(pred_y)
pred_y.dtype
pred_y = pred_y.astype('int')
pred_y.dtype
integDF['PassengerId'].dtype
passengerID = integDF.ix[891:,'PassengerId']
print(len(passengerID),len(pred_y))
passengerID.tail()
print(pred_y.shape)
print(passengerID.shape)
print(type(pred_y))
print(type(passengerID))
predDF = pd.DataFrame({'passengerID':passengerID,'Survived':pred_y})
predDF.head()
# 导入文件
predDF.to_csv('titanic_pred.csv',index=False )