泰坦尼克号幸存者预测
版权声明
本文首发于微信公众号
沁机迈可思(zw_life-long_doing)
无需授权即可转载
转载时请注明出处
有这么一家银行,他家的信用卡非常受人欢迎。我们假设这家银行批准某种信用卡申请,记作“1”;而它拒绝某种信用卡的申请,则记为“0”。某天,你想要去这家银行申请信用卡,能知道银行将批准你使用某种信用卡的概率吗?
当然可以。最简单的方法就是使用逻辑回归算法。
看到算法两个字,大多数人会觉得头大,因为不懂嘛。但简单的讲,我们常说的算法,就是套路。即用这个套路来解决实际问题。
那逻辑回归算法解决什么问题呢?
我们假设有一组数据,它服从伯努利分布(也称0-1分布)。那么逻辑回归算法则通过极大化似然函数的方法,运用梯度下降来求解参数,达到将数据二分的目的。
所以说,虽然逻辑回归带有“回归”两个字,但它最终解决的是二分类问题。即判断某数据更大概率是属于A结果,还是B结果。
这里解释两个概念:
回归:指研究一组变量(y1, y2, ……, yi)和另一组变量(x1, x2, ……, xi)之间关系的一个统计分析方法。
最大似然函数:在统计学中,用来估计一个概率模型参数的一种方法。可以利用已知的样本结果,反推最大概率导致这个结果的参数值。
梯度下降法:它是一个一阶最优算法,目的是为了找到一个函数的极小值。梯度方向表示了函数增长速度最快的方向,当我们需要求解函数极小值的时候,以函数上一点为起点,朝着梯度的相反方向迭代搜索,就能求解该函数的极小值。
那么,我们知道了逻辑回归的含义和作用,但是要怎么使用呢?本文就用逻辑回归算法,来预测一下泰坦尼克号海难中,哪一类的乘客更容易生存下来。
首先,在kaggle平台上下载好我们需要的数据,并用python加载。
importpandasaspd
frompandasimportSeries,DataFrame
# 自己的文件路径
train=pd.read_csv('/Users/weizhong/Desktop/Titanic_train.csv')
test=pd.read_csv('/Users/weizhong/Desktop/Titanic_test.csv')
# 看看数据表的基本信息
print('训练数据信息:',train.shape,'预测数据信息:',test.shape)
数据集,是我们用来训练模型用的数据,有891行,12列数据,数据集是我们最后用模型来预测的数据,有418行,11列数据,对比训练数据集少了这列内容。因为这一列是我们要预测的结果嘛。
虽然是两个数据集,但是二者的差别并不大。因此,我们仍然可以将两个数据集合并来进行数据处理。
full=train.append(test,ignore_index=True)
print('合并后的数据:',full.shape)
full.head()
然后我们用语句看看数据的基本情况。
通过这个描述信息,我们发现该数据集是有缺失数据的。因此,我们可以使用语句来进一步查看该数据集的基本情况。
不难发现,在、、、这四列的数据是有不同程度缺失的。因此,我们先进行缺失值的处理。一般情况下,我们处理缺失值有三种方法:
数值型数据,用均值填充;
分类数据,用最常见的类别填充;
使用模型预测预测缺失值,如K-NN模型。
这里我们就简单粗暴一点,用前两种方法。
# 数值型数据的缺失值填充
full['Age']=full['Age'].fillna(full['Age'].mean())
full['Fare']=full['Fare'].fillna(full['Fare'].mean())
# 字符串类型数据填充
full['Cabin']=full['Cabin'].fillna('U')# U=unkown
full['Embarked']=full['Embarked'].fillna('S')
缺失值填充好了,接下来就是对现有的数据标签进行特征工程操作了。为什么需要有这么一步?国外一位大牛这么形容特征工程:
Feature Engineering is manually designing what the input x’s should be.
为什么在数据处理中,“特征工程”会如此的重要呢?我们都知道,机器学习算法的最终目的,是为了预测未知数据。先不说算法的好坏会影响最终结果,数据的好坏也会影响到最终结果。
因此,特征工程的作用就是从原始数据最大限度的提取出我们需要的数据,供模型与算法使用。但你也知道,我们在处理数据的时候,字符串类型是不方便我们进一步处理的,因为我们在选取特征之前,需要对数据集进行几个基本操作:
数值型:直接使用;
时间序列:转成单独年、月、日;
分类数据:用数值代替类别。使用one-hot编码。
我们将数据集中的数据简单分个类。
发现我们有5项分类数据需要进行数值化处理(船票编号因为没有实际意义,所以不做处理)。但是因为在处理两类以上数据的时候,会更加高效。因此在性别这一栏,我们就直接用赋值法修改。
sex_dict={'male':1,'female':}
# 用map函数批量对一维数组中的每个数据应用某规则
full['Sex']=full['Sex'].map(sex_dict)
在剩下的5项中,、因为是重复的进行编码,因此这里就仅仅以Embarked的编码代码为例。
# 登船港口
embarked_df=DataFrame()
embarked_df=pd.get_dummies(full['Embarked'],prefix='Embarked')
# 将数据添加到原数据集中
full=pd.concat([full,embarked_df],axis=1)
# 删除新表中“Embarked”这一列
full=full.drop('Embarked',axis=1,inplase=True)
效果图如下。
再来说说Cabin这一列的编码。从数据表中,我们可以看到,这一列的数据多是“一个字母+数字”的形式。由于我们需要的是哪一类的客舱号,而不是具体的数字,所以,这里我们仅仅是需要客舱号的首字母,知道该客舱是属于哪一类客舱即可。因此,在上面的代码基础上,我们需要先对这一列的数据进行批量的提取之后,再进行编码。(编码步骤一样,因此这里就只是展示提取的代码)
# 运用lambda语句构建一个简易的自定义函数
full['Cabin']=full['Cabin'].map(lambdax:x[])
比较困难一点的是姓名这一列。
或许说你叫什么名字,对最后的预测帮助不大。但是你的头衔就说不准啦。通过上图,可以看出,在每一个名字的中间,会有这个人的头衔称谓。通过这个头衔,不仅可以知道他们的性别,而且可以知道他们的地位阶级。因此,先用函数将头衔分离出来。
defname_title(f):str1=f.split(',')[1]str2=str1.split('.')[]# strip()函数主要移除字符串头尾指定字符,默认是空格str3=str2.strip()returnstr3
title_df=DataFrame()
name_ser=full['Name']
title_df=name_ser.map(name_title)
但是,1300多行数据,我们不能说只有“Mr”和“Mrs”这两类头衔,因此我们先用语句将数据去重看看。这里要注意,一定不要在原代码中操作,重新复制一个变量查看,避免内容错乱。
我的乖乖,总共有18个头衔。但是因为泰坦尼克号在三个不同国家的港口停靠(分别是英国的南安普顿、法国的瑟堡和爱尔兰的昆士敦),所以不排除这些头衔里面有重复的情况。因此,我们按照网上划分,先将这些头衔分成Officer(政府官员)、Royalty(王室/皇室)、Mr(男士)、Mrs(已婚女士)、Miss(未婚女士)、Master(有技能的人)这六大类,再进行编码。
到此,分类数据倒是被我们处理完了。但是家庭情况,我们仍是需要汇总归类处理一下。虽说原表中已有和两列数据,但是他们只是记录一个家庭的人数,并没有表现出这个家庭的大小。因此,我们这里讲它进行汇总分类处理。
family_df=DataFrame()
# 家庭总人数需要加上自己
family_df['Family_size']=full['SlibSp']+full['Parch']+1
# 对家庭大小进行条件判断
family_df['Family_small']=family_df['Family_df'].map(lambdaa:1ifa==1else)
family_df['Fmaily_middle']=family_df['Family_df'].map(lambdaa:1ifa>=2anda
family_df['Family_large']=family_df['Family_df'].map(lambdaa:1ifa>5else)
# 将家庭总数表和类别表添加进原表
full=pd.concat([full,family_df],axis=1)
现在,所有的数据处理完了,我们看看这个数据集的相关系数。
或许你会说,这里有太多列了,不如画热力图来的直观一些。但是你可别忘记了,我们需要预测的是幸存者。因此,我们需要的是Survived这列的相关系数信息。
从这列结果来看,相关系数最高的,是已婚女士和未婚女士,最低的果然是男士。看来当时的绅士礼仪,真是深入到了各个阶层……好了,不扯远了,既然我们知道了与最终幸存呈现正相关的特征是哪些,那么我们接下来要做的就是选取要训练的特征了。这里我们重新赋值一个变量。
但是因为我们在清洗数据的时候,是讲测试集合预测集合并在一起进行清洗的,因此我们最后需要拆分出训练数据集和预测数据集。
最后,就是关键的训练模型了。
# 拆分训练数据
fromsklearn.model_selectionimporttrain_test_split
# 拆分成80%的训练集合20%的测试集
train_X,test_X,train_y.test_y=train_test_split(source_X,source_y,train_size=.8)
# 用训练集来训练数据
fromsklearn.linear_modelimportLogisticRegression
model=LogisticRegression()model.fit(train_X,train_y)
# 用测试数据来评估模型
model.score(test_X,test_y)
训练了模型之后,我们用分离出来的测试数据和来评估一个模型的准确率。
这里需要说明一点的是,因为我们训练的数据太小,所以每次重新运行代码的时候,这里的正确率的波动会比较大。
训练好了模型之后,就是运用模型了。但是因为在kaggle中提交预测结果要求的是整形,因此我们还需要将数据类型转换为类型,并输出“.csv”格式的文件。
pred_y=model.predict(pred_X)
# 将数据类型转换成整形,并匹配对应的乘客编号
pred_y=pred_y.astype(int)
passengerId=full.loc[source_row:,'PassengerId']
# 汇总成一个数据集
pred_df=DataFrame({'PassengerId':passengerId,'Survived':pred_y})
pred_df.to_csv('Titanic_pred.csv',index=False)
当我解决玩一个项目,满怀欣喜的将结果上传至kaggle之后,看着自己的排名仅仅才top49%,排名5000多名去了,有点惨不忍睹。黯然神伤……
经过了这次项目,小小的总结一下:
从整个项目来看,数据清洗几乎占据了整个项目60%的工作量。而且这里面的“特征工程”又是极为重要的一环。因此,鉴于编码能对分类数据进行数值化处理,共模型使用,需要熟练运用。
数据特征的选取质量,直接影响这最后模型的预测准确度。
在数据总量既定的情况下,用多个模型进行预测,最后再选出最合适的模型是不错的选择。我相信下次再做这个项目,就不仅仅是top49%这么简单了。
我叫钟小韦,爱折腾的天府小生,期待与你一同成长。