Kaggle泰坦尼克数据科学解决方案

原文地址如下:

https://www.kaggle.com/startupsci/titanic-data-science-solutions

看完一遍,什么也没记住,于是干脆直接翻译一遍。

然鹅,依旧没记住什么。

----------------------------------------------------------------

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px SimSun }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px SimSun }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Times New Roman"; min-height: 15.0px }
p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px SimSun }
p.p4 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Calibri }
p.p5 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px SimSun }
p.p6 { margin: 0.0px 0.0px 0.0px 0.0px; text-indent: 36.0px; font: 12.0px SimSun }
p.p7 { margin: 0.0px 0.0px 0.0px 18.0px; font: 12.0px "Times New Roman"; min-height: 15.0px }
p.p8 { margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Menlo }
p.p9 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Calibri; color: #0079cd }
p.p10 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Times New Roman" }
p.p11 { margin: 18.0px 0.0px 12.0px 0.0px; font: 13.5px Helvetica }
p.p12 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.5px Times }
p.p13 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.5px Times; min-height: 13.0px }
p.p14 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.5px Helvetica }
p.p15 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #839496 }
p.p16 { margin: 0.0px 0.0px 0.0px 0.0px; font: 8.0px Menlo; color: #839496 }
p.p17 { margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px "Times New Roman"; min-height: 10.0px }
p.p18 { margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Calibri }
p.p19 { margin: 0.0px 0.0px 0.0px 0.0px; font: 8.0px Menlo; color: #839496; min-height: 9.0px }
p.p20 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px Calibri }
p.p21 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #839496; min-height: 13.0px }
p.p22 { margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Menlo; min-height: 10.0px }
p.p23 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Menlo; color: #839496 }
p.p24 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px Menlo; color: #839496; min-height: 11.0px }
p.p25 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.5px Menlo; color: #839496 }
p.p26 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px "Times New Roman"; min-height: 16.0px }
p.p27 { margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Menlo; color: #839496 }
p.p28 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.5px "Times New Roman"; min-height: 11.0px }
p.p29 { margin: 0.0px 0.0px 0.0px 0.0px; font: 10.0px "Times New Roman"; min-height: 11.0px }
p.p30 { margin: 0.0px 0.0px 0.0px 0.0px; font: 16.0px "Times New Roman"; min-height: 18.0px }
li.li4 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Calibri }
li.li5 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px SimSun }
span.s1 { font: 16.0px Calibri }
span.s2 { font: 12.0px SimSun }
span.s3 { font: 12.0px "PingFang SC" }
span.s4 { font: 12.0px Calibri }
span.s5 { color: #929292 }
span.s6 { color: #011993 }
span.s7 { color: #009193 }
span.s8 { color: #0433ff }
span.s9 { text-decoration: underline }
span.s10 { font: 10.5px Times }
span.s11 { font: 12.0px "Times New Roman" }
span.s12 { font: 9.0px SimSun }
span.s13 { font: 16.0px "Times New Roman" }
span.s14 { font: 16.0px SimSun }
span.s15 { font: 14.0px Calibri }
span.s16 { font: 12.0px Helvetica }
span.Apple-tab-span { white-space: pre }
table.t1 { border-collapse: collapse }
td.td1 { background-color: #ffffff; border-style: solid; border-width: 1.0px 1.0px 1.0px 1.0px; border-color: #cbcbcb #cbcbcb #cbcbcb #cbcbcb; padding: 0.0px 5.0px 0.0px 5.0px }
ol.ol1 { list-style-type: decimal }
ol.ol2 { list-style-type: lower-alpha }

泰坦尼克数据科学解决方案:

1. 工作流程步骤:

在 Data Science Solutions book 这本书里,描述了在解决一个竞赛问题时所需要做的具体工作流程:

  1. 问题的定义
  2. 获取训练数据以及测试数据
  3. 加工、准备以及清洗数据
  4. 分析、识别数据的模式,并对数据做可视化
  5. 建模、预测,并解决问题
  6. 对结果做可视化,生成报告,并且展示问题的解决步骤和最终的解决方案
  7. 提交结果

以上的工作流程仅仅描述了一般的问题解决步骤,然而依然会有一些特殊的案例并不严格遵循以上流程:

  1. 我们可能会结合多个步骤。例如通过将数据可视化后直接进行分析
  2. 将某个步骤提前执行。例如在做数据加工前即开始对数据进行分析
  3. 在工作流程中多次进行某个步骤。例如在整个流程中会多次对数据进行可视化
  4. 完全弃用一个步骤。例如在非竞赛场合可能并不需要做提交结果的步骤

2. 问题的定义:

一般的竞赛网站(如 Kaggle)会在提供训练数据以及测试数据的同时,给出问题的定义。对与此次的“泰坦尼克号幸存者”问题的定义如下:

“在训练数据中,提供了在泰坦尼克号上乘客的具体数据以及他们是否在那次灾难中存活的信息。参赛者能否通过已有的训练数据训练出一个模型,此模型需要根据输入的测试数据里乘客信息,来预测此乘客是否能在灾难中存活”

我们可能也想要通过问题描述获取更多有关此问题的信息。在此问题的描述中,比较有意义的描述如下:

  1. 泰坦尼克号在1912年4月15日与冰山碰撞后沉没。在一共2224名乘客与船员里,有1502人不幸逝世。这个信息即表明了此次事件中生还率为32%。
  2. 一个使得在这次灾难中有如此之大死亡率的原因是:在船上没有足够的救生船提供给乘客以及船员
  3. 尽管在此次灾难中生还存在运气的成分,但是仍旧会有些群体的生还率高于其他人,如女人、小孩,以及上等仓的人

3. 工作流程里的目标:

数据科学解决方案的流程主要有7个目标:

  1. 分类:我们可能想对样本分类,也希望根据需要解决的目标去理解不同类别之间的隐藏关系
  2. 相互关系:我们可以根据训练集里可用的特征来解决一个问题。那到底在数据集里的哪些特征会对解决问题起着至关重要的作用呢?从统计学上来说,是否在某个特征与问题的解之间存在某种联系?如果这个特征的值改变后,相应问题的解是否也会改变呢?反过来的情况是否也是如此呢?这个可以通过对数据集里的数值型以及离散型的特征做测试来得到。我们可能也希望得到特征之间的关系,而不是直接得到特征与问题解之间的关系。找到一些特定属性之间的关联性可能会在创建、补全以及修正特征上起到一定作用
  3. 转换:在建模的阶段,我们需要准备数据。根据模型、算法的选择,我们可能需要将所有的特征转化为同等的数值型特征。例如将文本型数据转换为数值型数据
  4. 补全数据:在数据准备的阶段中,我们可能仍然需要预测某些特征下丢失的数据值。更重要的是,模型可能在无丢失数据时表现的更好
  5. 修正数据:我们可能仍然需要分析给定的训练数据集里某些特征下的错误数据以及可能是错误的数据,并且尝试去修正这些数据或者除去这些包含错误数据的样本。一个可行的方案是在我们样本里或特征里检测所有异常值。如果某个特征对我们的问题分析毫无帮助,或者会对结果产生影响,那我们可能还需要完全丢弃这个特征。
  6. 创造数据:我们是否能够根据已存在的某个或某几个特征创建一个新的特征呢?并让新特征遵从“相互关系”、“转换”以及“数据完整(补全数据)”的目标
  7. 制图:如何根据原数据集以及要解决问题,对数据做合适的可视化图

4. 会用到的库:

以下是在接下来的实验里会用到的一些库:

# data analysis and wrangling

import pandas as pd

import numpy as np

import random as rnd

# visualization

import seaborn as sns

import matplotlib.pyplot as plt

# machine learning

from sklearn.linear_model import LogisticRegression

from sklearn.svm import SVC, LinearSVC

from sklearn.ensemble import RandomForestClassifier

from sklearn.neighbors import KNeighborsClassifier

from sklearn.naive_bayes import GaussianNB

from sklearn.linear_model import Perceptron

from sklearn.linear_model import SGDClassifier

from sklearn.tree import DecisionTreeClassifier

5. 获取数据:

我们可以用python 的 Pandas 来帮助我们处理数据。首先可以将训练数据以及测试数据读入到Pandas 的 DataFrames 里。我们也会将这两个数据集结合起来,用于在两个数据集上同时做一些特定的操作。

# set pandas

pd.set_option(‘display.width‘, 1000)

# use pandas to manage data

train_df = pd.read_csv(‘data/train.csv‘)

test_df = pd.read_csv(‘data/test.csv‘)

combine = [train_df, test_df]

6. 通过描述数据来分析:

Pandas 也可以帮助我们描述数据集。我们可以通过以下问答的方式来查看数据集:

1. 在数据集中有哪些可用的特征?

首先需要注意的是,数据集里特征的描述已经在问题描述里给出了,此次数据集里的特征描述如下:

https://www.kaggle.com/c/titanic/data

------------------------------------------------------------------------------------------------------

主要内容为:

Data Dictionary


Variable


Definition


Key


survival


Survival


0 = No, 1 = Yes


pclass


Ticket class


1 = 1st, 2 = 2nd, 3 = 3rd


sex


Sex


Age


Age in years


sibsp


# of siblings / spouses aboard the Titanic


parch


# of parents / children aboard the Titanic


ticket


Ticket number


fare


Passenger fare


cabin


Cabin number


embarked


Port of Embarkation


C = Cherbourg, Q = Queenstown, S = Southampton

Variable Notes

pclass: A proxy for socio-economic status (SES)

1st = Upper

2nd = Middle

3rd = Lower

age: Age is fractional if less than 1. If the age is estimated, is it in the form of xx.5

sibsp: The dataset defines family relations in this way...

Sibling = brother, sister, stepbrother, stepsister

Spouse = husband, wife (mistresses and fiancés were ignored)

parch: The dataset defines family relations in this way...

Parent = mother, father

Child = daughter, son, stepdaughter, stepson

Some children travelled only with a nanny, therefore parch=0 for them.

------------------------------------------------------------------------------------------------------

在 Pandas里:

>>> print(train_df.columns.values)

[‘PassengerId‘ ‘Survived‘ ‘Pclass‘ ‘Name‘ ‘Sex‘ ‘Age‘ ‘SibSp‘ ‘Parch‘

‘Ticket‘ ‘Fare‘ ‘Cabin‘ ‘Embarked‘]

2. 哪些特征是离散型的?

这些离散型的数值可以将样本分类为一系列相似的样本。在离散型特征里,它们的数值是基于名词的?还是基于有序的?又或是基于比率的?还是基于间隔类的?除此之外,这个可以帮助我们为数据选择合适的图形做可视化。

在这个问题中,离散型的变量有:Survived,Sex 和 Embarked。基于序列的有:Pclass

3. 哪些特征是数值型?

哪些特征是数值型的?这些数据的值随着样本的不同而不同。在数值型特征里,它们的值是离散的还是连续的?又或者是基于时间序列?除此之外,这个可以帮助我们为数据选择合适的图形做可视化。

在这个问题中,连续型的数值特征有:Age,Fare。离散型数值有:SibSp,Parch

>>> train_df.head()

4. 哪些特征是混合型数据?

数值型、字母数值型数据在同一特征下面。这些有可能是我们需要修正的目标数据。

在这个问题中,Ticket是混合了数值型以及字母数值型的数据类型,Cabin是字母数值型数据

5. 哪些特征可能包含错误数据或打字错误?

在大型数据集里要发现这些可能比较困难,然而通过观察小型的数据集里少量的样本,可能也可以完全告诉我们哪些特征需要修正。

在这个问题中,Name的特征可能包含错误或者打字错误,因为会有好几种方法来描述名字

>>> train_df.tail()

6. 哪些特征包含空格,null或者空值

这些空格,null值或者空值很可能需要修正。

在这个问题中:

  1. 这些特征包含null值的数量大小为:Cabin > Age > Embarked
  2. 在训练集里有不完整数据的数量的大小为:Cabin > Age

7.每个特征下的数据类型是什么?

这个可以在我们做数据转换时起到较大的帮助。

在这个问题中:

  1. 有7个特征是int型或float 型。在测试数据集里有6个
  2. 有5个特征是string(object)类型

>>> train_df.info()

<class ‘pandas.core.frame.DataFrame‘>

RangeIndex: 891 entries, 0 to 890

Data columns (total 12 columns):

PassengerId    891 non-null int64

Survived       891 non-null int64

Pclass         891 non-null int64

Name           891 non-null object

Sex            891 non-null object

Age            714 non-null float64

SibSp          891 non-null int64

Parch          891 non-null int64

Ticket         891 non-null object

Fare           891 non-null float64

Cabin          204 non-null object

Embarked       889 non-null object

dtypes: float64(2), int64(5), object(5)

memory usage: 83.6+ KB

>>> test_df.info()

<class ‘pandas.core.frame.DataFrame‘>

RangeIndex: 418 entries, 0 to 417

Data columns (total 11 columns):

PassengerId    418 non-null int64

Pclass         418 non-null int64

Name           418 non-null object

Sex            418 non-null object

Age            332 non-null float64

SibSp          418 non-null int64

Parch          418 non-null int64

Ticket         418 non-null object

Fare           417 non-null float64

Cabin          91 non-null object

Embarked       418 non-null object

dtypes: float64(2), int64(4), object(5)

memory usage: 36.0+ KB

8. 在样本里,数值型特征的数值分布是什么样的?

这个可以帮助我们初步了解:训练数据集如何体现了实际问题。

在这个问题中:

  1. 一共有891个样本
  2. Survived的标签是通过0或1来区分
  3. 大概38%的样本是survived
  4. 大多数乘客(>75%)没有与父母或是孩子一起旅行
  5. 大约30%的乘客有亲属和/或配偶一起登船
  6. 票价的差别非常大,少量的乘客(<1%)付了高达$512的费用
  7. 很少的乘客(<1%)年纪在64-80之间

我们可以通过以下方式获取上述信息:

>>> train_df.describe()

PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare

count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000

mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208

std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429

min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000

25%     223.500000    0.000000    2.000000   20.125000    0.000000    0.000000    7.910400

50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200

75%     668.500000    1.000000    3.000000   38.000000    1.000000    0.000000   31.000000

max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

# 通过使用 percentiles=[.61, .62] 来查看数据集可以了解到生存率为 38%

>>> train_df.describe(percentiles=[.61, .62])

PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare

count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000

mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208

std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429

min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000

50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200

61%     543.900000    0.000000    3.000000   32.000000    0.000000    0.000000   23.225000

62%     552.800000    1.000000    3.000000   32.000000    0.000000    0.000000   24.150000

max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

# 通过使用 percentiles=[.75, .8] 来查看Parch的分布

>>> train_df.describe(percentiles=[.75, .8])

PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare

count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000

mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208

std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429

min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000

50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200

75%     668.500000    1.000000    3.000000   38.000000    1.000000    0.000000   31.000000

80%     713.000000    1.000000    3.000000   41.000000    1.000000    1.000000   39.687500

max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

# 通过使用 percentile=[.68, .69] 来查看SibSp的分布

>>> train_df.describe(percentiles=[.68, .69])

PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare

count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000

mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208

std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429

min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000

50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200

68%     606.200000    1.000000    3.000000   35.000000    0.000000    0.000000   26.307500

69%     615.100000    1.000000    3.000000   35.000000    1.000000    0.000000   26.550000

max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

# 通过使用 percentile=[.1, .2, .3, .4, .5, .6, .7, .8, .9, .99] 来查看Age和Fare的分布

>>> train_df.describe(percentiles=[.1, .2, .3, .4, .5, .6, .7, .8, .9, .99])

PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare

count   891.000000  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000

mean    446.000000    0.383838    2.308642   29.699118    0.523008    0.381594   32.204208

std     257.353842    0.486592    0.836071   14.526497    1.102743    0.806057   49.693429

min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000

10%      90.000000    0.000000    1.000000   14.000000    0.000000    0.000000    7.550000

20%     179.000000    0.000000    1.000000   19.000000    0.000000    0.000000    7.854200

30%     268.000000    0.000000    2.000000   22.000000    0.000000    0.000000    8.050000

40%     357.000000    0.000000    2.000000   25.000000    0.000000    0.000000   10.500000

50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200

60%     535.000000    0.000000    3.000000   31.800000    0.000000    0.000000   21.679200

70%     624.000000    1.000000    3.000000   36.000000    1.000000    0.000000   27.000000

80%     713.000000    1.000000    3.000000   41.000000    1.000000    1.000000   39.687500

90%     802.000000    1.000000    3.000000   50.000000    1.000000    2.000000   77.958300

99%     882.100000    1.000000    3.000000   65.870000    5.000000    4.000000  249.006220

max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

8. 在样本里,离散型数据的分布是什么?

在这个问题中:

  1. 各个乘客的Name 属性完全是唯一的(count=unique=891)
  2. Sex特征里65%为男性(top=male,fre=577/count=891)
  3. Cabin的count与unique并不相等,即说明有些乘客会共享一个cabin
  4. Embarked一共有种取值,其中从S港口登船的人最多
  5. Ticket的特征下,有22%左右的重复值(unique=681)

可以通过以下方法获得以上信息:

>>> train_df.describe(include=[‘O‘])

Name   Sex    Ticket Cabin Embarked

count                          891   891       891   204      889

unique                         891     2       681   147        3

top     Andrew, Mr. Edgardo Samuel  male  CA. 2343    G6        S

freq                             1   577         7     4      644

7. 基于以上数据分析后的假设

根据以上的数据分析步骤后,我们可以暂时得出以下假设。当然,我们也可以在之后验证这些假设。

相互关系:

我们想知道每个特征与Survival的相关性如何。我们希望能够今早的做这一步,并且将这些相关性特征匹配到建模后的相关性特征上。

补全数据:

  1. 我们可能会去补全Age特征下的数据,因为它一定是与存活率是相关的
  2. 我们可能会去补全Embarked特征下的数据,因为它可能与存活率或者其他重要的特征之间存在相关性

修正数据:

  1. Ticket特征可能需要从我们的分析中丢弃,因为它的数值重复率高达22%,并且Ticket与survival之间很可能并没有联系
  2. Cabin特征可能也需要丢弃,因为它的数值非常不完整,并且在训练集以及测试集里均包含较多的null值
  3. PassengerId特征可能也需要被丢弃,因为它对survival没任何作用
  4. Name特征相对来说不是特别规范,并且很有可能与survival之间没有直接联系,所以可能也应该被丢弃

创造数据:

  1. 我们可以根据Parch和SibSp的特征来创建一个新的Family特征,以此得到每个乘客有多少家庭成员登了船
  2. 我们可以对Name特征做进一步加工,提取出名字里的Title作为一个新的特征
  3. 我们可以为Age特征创建一个新的特征,将它原本的连续型数值特征转换为有序的离散型特征
  4. 我们也可以创建一个票价(Fare)范围的特征,如果它对我们的分析有帮助的话

分类:

根据之前的问题描述或者已有的数据,我们也可以提出以下假设:

  1. 女人(Sex=female)更有可能存活
  2. 孩子(Age<?)也更有可能存活
  3. 上等仓的乘客(Pclass=1)有更大的存活率

8. 基于通过pivoting features分析

为了验证之前的观察与假设,我们可以通过pivoting feature的方法简单的分析一下特征之间的相关性。

这种方法仅仅对那些没有特别多空值的属性有效,并且仅仅对那些分类型的(Sex)、有序型的(Pclass)以及离散型(SibSp,Parch)的特征才有意义。

1. Pclass:我们观察到Pclass=1与Survived的相关性较大(>0.5),所以可以考虑将此特征放入到之后的模型里

2. Sex:我们可以确认Sex=female有着高达74%的生存率

3. SibSp 和 Parch:这些特征下有些值与survived有相关性,但是有些又毫无相关性。所以我们可能需要基于这些单独的特征或一系列特征创建一个新特征,以做进一步分析

以上结论可以通过下面的操作获取:

>>> train_df[[‘Pclass‘, ‘Survived‘]].groupby([‘Pclass‘], as_index=False).mean().sort_values(by=‘Survived‘, ascending=False)

Pclass  Survived

0       1  0.629630

1       2  0.472826

2       3  0.242363

>>> train_df[[‘Sex‘, ‘Survived‘]].groupby([‘Sex‘], as_index=False).mean().sort_values(by=‘Survived‘, ascending=False)

Sex  Survived

0  female  0.742038

1    male  0.188908

>>> train_df[[‘SibSp‘, ‘Survived‘]].groupby([‘SibSp‘], as_index=False).mean().sort_values(by=‘Survived‘, ascending=False)

SibSp  Survived

1      1  0.535885

2      2  0.464286

0      0  0.345395

3      3  0.250000

4      4  0.166667

5      5  0.000000

6      8  0.000000

>>> train_df[[‘Parch‘, ‘Survived‘]].groupby([‘Parch‘], as_index=False).mean().sort_values(by=‘Survived‘, ascending=False)

Parch  Survived

3      3  0.600000

1      1  0.550847

2      2  0.500000

0      0  0.343658

5      5  0.200000

4      4  0.000000

6      6  0.000000

9.通过将数据可视化进行分析

现在我们可以通过将数据可视化对数据做进一步分析,并继续验证我们之前的假设是否正确

数值型特征与Survived之间的联系:

柱状图在用于分析连续型的数值特征时非常有用,如特征Age,它的柱状图数值范围(不同的年龄范围)可以帮助我们识别一些有用的模式。

通过使用默认或自定的数值范围(年龄范围),柱状图可以帮助我们描绘出样本所遵循的分布。

它可以帮助我们发现是否某些特定的年龄范围(如婴儿)有更高的存活率。

我们可以通过以下代码来画出Age的柱状图:

>>> g = sns.FacetGrid(train_df, col=‘Survived‘)

>>> g.map(plt.hist, ‘Age‘, bins=20)

>>> plt.show()

观察:

  1. 婴儿(Age<=4)有较高的生存率
  2. 老人(Age=80)全部生还
  3. 大量的15-25年纪的乘客没有生还
  4. 乘客主要在15-35的年纪范围内

结论:

以上简单的分析验证了我们之前的假设:

  1. 我们需要将Age考虑到训练模型里
  2. 为Age特征补全null值
  3. 我们应该band不同的年龄层

数值型与序列型特征之间的联系:

我们可以将多个特征组合,然后通过一个简单的图来识别它们之间的关系。这种方法可以应用在数值型以及分类型(Pclass)的特征里,因为它们的值都是数值型。

我们可以通过以下代码来画出Pclass的柱状图:

>>> grid = sns.FacetGrid(train_df, col=‘Survived‘, row=‘Pclass‘, size=2.2, aspect=1.6)

>>> grid.map(plt.hist, ‘Age‘, alpha=.5, bins=20)

>>> grid.add_legend()

>>> plt.show()

观察:

  1. Pclass=3 有着最多的乘客,但是他们大多数却没有存活。这也验证了我们之前在“分类”里的假设 #2
  2. 在Pclass=2和Pclass=3中,大多数婴儿活了下来,进一步验证了我们之前在“分类”里的假设 #2
  3. 大多数Pclass=1的乘客存活,验证我们之前在“分类”里的假设 #3
  4. Pclass根据Age的分布而改变

结论:

  1. 考虑将Pclass特征加入模型训练

离散型特征与Survived之间的联系:

现在我们可以查看离散型特征与survived之间的关系

我们可以通过以下方式将数据可视化:

>>> grid = sns.FacetGrid(train_df, row=‘Embarked‘, size=2.2, aspect=1.6)

>>> grid.map(sns.pointplot, ‘Pclass‘, ‘Survived‘, ‘Sex‘, palette=‘deep‘)

>>> grid.add_legend()

>>> plt.show()

观察:

  1. 女性乘客相对于男性乘客有着更高的存活率
  2. 唯一在Embarked=C中是例外,其中男性的生存率高于女性。从这点来看,Pclass和Embarked之间可能有联系 。
  3. Embarked和Survived之间可能并没有直接的联系。
  4. Males had better survival rate in Pclass=3 when compared with Pclass=2 for C and Q ports
  5. 对于Pclass=3以及男性乘客来说,Embarked的港口不同会导致存活率的不同

结论:

  1. 将Sex特征加入训练模型
  2. 补全Embarked特征下的数据并将此特征加入训练模型

离散型特征与数值型特征之间的联系:

我们可能也想找出离散型与数值型特征之间的关系。

我们可以考虑查看Embarked(离散非数值型),Sex(离散非数值型),Fare(连续数值型)与Survived(离散数值型)之间的关系

我们可以通过下方式将数据可视化:

>>> grid = sns.FacetGrid(train_df, row=‘Embarked‘, col=‘Survived‘, size=2.2, aspect=1.6)

>>> grid.map(sns.barplot, ‘Sex‘, ‘Fare‘, alpha=.5, ci=None)

>>> grid.add_legend()

>>> plt.show()

观察:

  1. 1. 付了高票价的乘客有着更高的生存率,验证了我们之前的假设
  2. 2. Embarked与生存率相关,验证了我们之前所做的假设

结论:

  1. 1. 考虑将Fare特征做不同的区间

10.加工数据

我们根据数据集以及题目的要求已经收集了一些假设与结论。到现在为止,我们暂时还没有对任何特征或数据进行处理。

接下来我们会根据之前做的假设与结论,以“修正数据”、“创造数据”以及“补全数据”为目标,对数据进行处理。

通过丢弃特征来修正数据:

这个步骤比较好的一个开始。通过丢弃某些特征,可以让我们处理更少的数据点,并让分析更简单。

根据我们之前的假设和结论,我们希望丢弃Cabin和Ticket这两个特征。

在这里需要注意的是,为了保持数据的一致,我们需要同时将训练集与测试集里的这两个特征均丢弃。

具体步骤如下:

>>> print("Before", train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)

Before (891, 12) (418, 11) (891, 12) (418, 11)

>>> train_df = train_df.drop([‘Ticket‘, ‘Cabin‘], axis=1)

>>> test_df = test_df.drop([‘Ticket‘, ‘Cabin‘], axis=1)

>>> combine = [train_df, test_df]

>>> print(‘After‘, train_df.shape, test_df.shape, combine[0].shape, combine[1].shape)

After (891, 10) (418, 9) (891, 10) (418, 9)

通过已有的特征创建新特征:

我们在丢弃Name与PassengerId这两个特征之前,希望从Name特征里提取出Titles的特征,并测试Titles与survival之间的关系。

在下面的代码中,我们通过正则提取了Title特征,正则表达式为(\w+\.),它会在Name特征里匹配第一个以“.”号为结束的单词。

同时,指定expand=False的参数会返回一个DataFrame。

>>> for dataset in combine:

dataset[‘Title‘] = dataset.Name.str.extract(‘([A-Za-z]+)\.‘, expand=False)

>>> pd.crosstab(train_df[‘Title‘], train_df[‘Sex‘])

Sex       female  male

Title

Capt           0     1

Col            0     2

Countess       1     0

Don            0     1

Dr             1     6

Jonkheer       0     1

Lady           1     0

Major          0     2

Master         0    40

Miss         182     0

Mlle           2     0

Mme            1     0

Mr             0   517

Mrs          125     0

Ms             1     0

Rev            0     6

Sir            0     1

我们可以使用高一些更常见的名字或“Rare”来代替一些Title,如:

for dataset in combine:

dataset[‘Title‘] = dataset[‘Title‘].replace([‘Lady‘, ‘Countess‘, ‘Capt‘,

‘Col‘, ‘Don‘, ‘Dr‘, ‘Major‘,

‘Rev‘, ‘Sir‘, ‘Jonkheer‘, ‘Dona‘], ‘Rare‘)

dataset[‘Title‘] = dataset[‘Title‘].replace(‘Mlle‘, ‘Miss‘)

dataset[‘Title‘] = dataset[‘Title‘].replace(‘Ms‘, ‘Miss‘)

dataset[‘Title‘] = dataset[‘Title‘].replace(‘Mme‘, ‘Mrs‘)

>>> train_df[[‘Title‘, ‘Survived‘]].groupby([‘Title‘], as_index=False).mean()

Title  Survived

0  Master  0.575000

1    Miss  0.702703

2      Mr  0.156673

3     Mrs  0.793651

4    Rare  0.347826

进一步的,我们可以将这些离散型的Title转换为有序的数值型:

# convert categorical titles to ordinal

title_mapping = {"Mr":1, "Miss":2, "Mrs":3, "Master":4, "Rare":5}

for dataset in combine:

dataset[‘Title‘] = dataset[‘Title‘].map(title_mapping)

dataset[‘Title‘] = dataset[‘Title‘].fillna(0)

>>> train_df.head()

现在我们可以放心的从训练集与测试集里丢弃Name特征。同时,我们也不再需要训练集里的PassengerId特征:

>>> train_df = train_df.drop([‘Name‘, ‘PassengerId‘], axis=1)

>>> test_df = test_df.drop([‘Name‘], axis=1)

>>> combine = [train_df, test_df]

>>> train_df.shape, test_df.shape

((891, 9), (418, 9))

>>> train_df.head()

Survived  Pclass     Sex   Age  SibSp  Parch     Fare Embarked  Title

0         0       3    male  22.0      1      0   7.2500        S      1

1         1       1  female  38.0      1      0  71.2833        C      3

2         1       3  female  26.0      0      0   7.9250        S      2

3         1       1  female  35.0      1      0  53.1000        S      3

4         0       3    male  35.0      0      0   8.0500        S      1

新的发现:

当我们画出Title,Age和Survived的图后,我们有了以下新的发现:

  1. Most titles band Age groups accurately. For example: Master title has Age mean of 5 years
  2. Survival among Title Age bands varies slightly
  3. 某些特定的title如Mme,Lady,Sir的乘客存活率较高,但某些title如Don,Rev,Jonkheer的乘客存活率不高

结论:

  1. 我们决定保留这个新的Title特征并加入到训练模型

转换一个离散型的特征

现在我们可以将一些包含字符串数据的特征转换为数值型特征,因为在很多建模算法里,输入的参数要求为数值型。

这个步骤可以让我们达到补全数据的目标。

我们可以从转换Sex特征开始,将female转换为1,male转换为0。我们可以将新的特征命名为Gender:

for dataset in combine:

dataset[‘Sex‘] = dataset[‘Sex‘].map({‘female‘:1, ‘male‘:0}).astype(int)

>>> train_df.head()

Survived  Pclass  Sex   Age  SibSp  Parch     Fare Embarked  Title

0         0       3    0  22.0      1      0   7.2500        S      1

1         1       1    1  38.0      1      0  71.2833        C      3

2         1       3    1  26.0      0      0   7.9250        S      2

3         1       1    1  35.0      1      0  53.1000        S      3

4         0       3    0  35.0      0      0   8.0500        S      1

补全连续数值型特征

现在我们可以开始为那些含null值或者丢失值的特征补全数据。我们首先会为Age特征补全数据。

现在我们总结一下三种补全连续数值型特征数据的方法:

1. 一个简单的方法是产生一个随机数,这个随机数的范围在这个特征的平均值以及标准差之间

2. 更精准的一个做法是使用与它相关的特征来做一个猜测。在这个案例中,我们发现Age,Gender和Pclass之间有关联。

所以我们会使用一系列Pclass和Gender特征组合后的中值,作为猜测的Age值。

所以我们会有一系列的猜测值如:当Pclass=1且Gender=0时,当Pclass=1且Gender=1时,等等…

3. 第三种方法是结合以上两种方法。我们可以根据一系列Pclass与Gender的组合,并使用第一种方法里提到的随机数来猜测缺失的Age值

方法1与方法3会在模型里引入随机噪音,多次的结果可能会有所不同。所以我们在这更倾向于使用方法2:

>>> grid = sns.FacetGrid(train_df, row=‘Pclass‘, col=‘Sex‘, size=2.2, aspect=1.6)

>>> grid.map(plt.hist, ‘Age‘, alpha=.5, bins=20)

>>> grid.add_legend()

>>> plt.show()

我们先准备一个空的数组来存储猜测的年龄,因为是Pclass与Gender的组合,所以数组大小为2x3:

>>> guess_ages = np.zeros((2, 3))

然后我们可以对Sex(0或1)和Pclass(1,2,3)进行迭代,并计算出在6中组合下所得到的猜测(Age)值:

for dataset in combine:

for i in range(0, 2):

for j in range(0, 3):

guess_df = dataset[(dataset[‘Sex‘] == i) & (dataset[‘Pclass‘] == j+1)][‘Age‘].dropna()

age_guess = guess_df.median()

# Convert random age float to nearest .5 age

guess_ages[i, j] = int(age_guess / 0.5 + 0.5) * 0.5

for i in range(0, 2):

for j in range(0, 3):

dataset.loc[ (dataset.Age.isnull()) & (dataset.Sex == i) & (dataset.Pclass == j+1),

‘Age‘] = guess_ages[i,j]

dataset[‘Age‘] = dataset[‘Age‘].astype(int)

>>> train_df.head()

Survived  Pclass  Sex  Age  SibSp  Parch     Fare Embarked  Title

0         0       3    0   22      1      0   7.2500        S      1

1         1       1    1   38      1      0  71.2833        C      3

2         1       3    1   26      0      0   7.9250        S      2

3         1       1    1   35      1      0  53.1000        S      3

4         0       3    0   35      0      0   8.0500        S      1

现在我们对Age分段,并查看每段与Survived之间的相关性:

>>> train_df[‘AgeBand‘] = pd.cut(train_df[‘Age‘], 5)

>>> train_df[[‘AgeBand‘, ‘Survived‘]].groupby([‘AgeBand‘], as_index=False).mean().sort_values(by=‘AgeBand‘, ascending=True)

AgeBand  Survived

0  (-0.08, 16.0]  0.550000

1   (16.0, 32.0]  0.337374

2   (32.0, 48.0]  0.412037

3   (48.0, 64.0]  0.434783

4   (64.0, 80.0)  0.090909

然后我们根据上面的分段,使用有序的数值来替换Age里的值:

for dataset in combine:

dataset.loc[ dataset[‘Age‘] <= 16, ‘Age‘] = 0

dataset.loc[(dataset[‘Age‘] > 16) & (dataset[‘Age‘] <= 32), ‘Age‘] = 1

dataset.loc[(dataset[‘Age‘] > 32) & (dataset[‘Age‘] <= 48), ‘Age‘] = 2

dataset.loc[(dataset[‘Age‘] > 48) & (dataset[‘Age‘] <= 64), ‘Age‘] = 3

dataset.loc[ dataset[‘Age‘] > 64, ‘Age‘]

>>> train_df.head()

Survived  Pclass  Sex  Age  SibSp  Parch     Fare Embarked  Title       AgeBand

0         0       3    0    1      1      0   7.2500        S      1  (16.0, 32.0]

1         1       1    1    2      1      0  71.2833        C      3  (32.0, 48.0]

2         1       3    1    1      0      0   7.9250        S      2  (16.0, 32.0]

3         1       1    1    2      1      0  53.1000        S      3  (32.0, 48.0)

4         0       3    0    2      0      0   8.0500        S      1  (32.0, 48.0)

接着我们可以丢弃AgeBand特征:

>>> train_df = train_df.drop([‘AgeBand‘], axis=1)

>>> combine = [train_df, test_df]

>>> train_df.head()

Survived  Pclass  Sex  Age  SibSp  Parch     Fare Embarked  Title

0         0       3    0    1      1      0   7.2500        S      1

1         1       1    1    2      1      0  71.2833        C      3

2         1       3    1    1      0      0   7.9250        S      2

3         1       1    1    2      1      0  53.1000        S      3

4         0       3    0    2      0      0   8.0500        S      1

通过已有的特征组合出新特征

现在我们可以通过组合Parch和SibSp特征,创建一个新的FamilySize特征。这个步骤可以让我们从数据集里丢弃Parch与SibSp特征。

for dataset in combine:

dataset[‘FamilySize‘] = dataset[‘SibSp‘] + dataset[‘Parch‘] + 1

>>> train_df[[‘FamilySize‘, ‘Survived‘]].groupby([‘FamilySize‘], as_index=False).mean().sort_values(by=‘Survived‘, ascending=False)

FamilySize  Survived

3           4  0.724138

2           3  0.578431

1           2  0.552795

6           7  0.333333

0           1  0.303538

4           5  0.200000

5           6  0.136364

7           8  0.000000

8          11  0.000000

接着我们可以创建另一个名为IsAlone的特征:

for dataset in combine:

dataset[‘IsAlone‘] = 0

dataset.loc[dataset[‘FamilySize‘] == 1, ‘IsAlone‘] = 1

>>> train_df[[‘IsAlone‘, ‘Survived‘]].groupby([‘IsAlone‘], as_index=False).mean()

IsAlone  Survived

0        0  0.505650

1        1  0.303538

基于上面的数据表现,我们现在可以丢弃Parch、SibSp以及FamilySize的特征,保留IsAlone的特征:

>>> train_df = train_df.drop([‘Parch‘, ‘SibSp‘, ‘FamilySize‘], axis=1)

>>> test_df = test_df.drop([‘Parch‘, ‘SibSp‘, ‘FamilySize‘], axis=1)

>>> combine = [train_df, test_df]

>>> train_df.head()

Survived  Pclass  Sex  Age     Fare Embarked  Title  IsAlone

0         0       3    0    1   7.2500        S      1        0

1         1       1    1    2  71.2833        C      3        0

2         1       3    1    1   7.9250        S      2        1

3         1       1    1    2  53.1000        S      3        0

4         0       3    0    2   8.0500        S      1        1

我们还可以通过结合Pclass 和 Age来创建一个新的特征:

for dataset in combine:

dataset[‘Age*Class‘] = dataset.Age * dataset.Pclass

>>> train_df.loc[:, [‘Age*Class‘, ‘Age‘, ‘Pclass‘]].head(10)

Age*Class  Age  Pclass

0          3    1       3

1          2    2       1

2          3    1       3

3          2    2       1

4          6    2       3

5          3    1       3

6          3    3       1

7          0    0       3

8          3    1       3

9          0    0       2

补全一个离散型的特征

Embarked特征主要有三个值,分别为S,Q,C,对应了三个登船港口。在训练集里,这个有2个缺失值,我们会使用频率最高的值来填充这个缺失值。

>>> freq_port = train_df.Embarked.dropna().mode()[0]

>>> freq_port

‘S‘

for dataset in combine:

dataset[‘Embarked‘] = dataset[‘Embarked‘].fillna(freq_port)

>>> train_df[[‘Embarked‘, ‘Survived‘]].groupby([‘Embarked‘], as_index=False).mean().sort_values(by=‘Survived‘, ascending=False)

Embarked  Survived

0        C  0.553571

1        Q  0.389610

2        S  0.339009

将离散型特征转换为数值型

我们现在可以将离散型的Embarked特征转换为数值型特征

for dataset in combine:

dataset[‘Embarked‘] = dataset[‘Embarked‘].map({‘S‘: 0, ‘C‘: 1, ‘Q‘: 2}).astype(int)

>>> train_df.head()

Survived  Pclass  Sex  Age     Fare  Embarked  Title  IsAlone  Age*Class

0         0       3    0    1   7.2500         0      1        0          3

1         1       1    1    2  71.2833         1      3        0          2

2         1       3    1    1   7.9250         0      2        1          3

3         1       1    1    2  53.1000         0      3        0          2

4         0       3    0    2   8.0500         0      1        1          6

补全数值型特征

现在我们可以开始为测试集里的Fare特征补全数据。在补全时,我们可以使用最频繁出现的数据用于补全缺失值。

(我们也可以将Fare的数值做四舍五入,将它精确到2位)

>>> test_df[‘Fare‘].fillna(test_df[‘Fare‘].dropna().median(), inplace=True)

>>> test_df.head()

PassengerId  Pclass  Sex  Age     Fare  Embarked  Title  IsAlone  Age*Class

0          892       3    0    2   7.8292         2      1        1          6

1          893       3    1    2   7.0000         0      3        0          6

2          894       2    0    3   9.6875         2      1        1          6

3          895       3    0    1   8.6625         0      1        1          3

4          896       3    1    1  12.2875         0      3        0          3

接下来我们将Fare分段:

>>> train_df[‘FareBand‘] = pd.qcut(train_df[‘Fare‘], 4)

>>> train_df[[‘FareBand‘, ‘Survived‘]].groupby([‘FareBand‘], as_index=False).mean().sort_values(by=‘FareBand‘, ascending=True)

FareBand  Survived

0   (-0.001, 7.91]  0.197309

1   (7.91, 14.454]  0.303571

2   (14.454, 31.0]  0.454955

3  (31.0, 512.329)  0.581081

根据分段后的特征FareBand,将Fare转换为有序的数值型特征:

for dataset in combine:

dataset.loc[ dataset[‘Fare‘] <= 7.91, ‘Fare‘] = 0

dataset.loc[(dataset[‘Fare‘] > 7.91) & (dataset[‘Fare‘] <= 14.454), ‘Fare‘] = 1

dataset.loc[(dataset[‘Fare‘] > 14.454) & (dataset[‘Fare‘] <= 31), ‘Fare‘] = 2

dataset.loc[dataset[‘Fare‘] > 31, ‘Fare‘] = 3

dataset[‘Fare‘] = dataset[‘Fare‘].astype(int)

>>> train_df = train_df.drop([‘FareBand‘], axis=1)

>>> combine = [train_df, test_df]

>>> train_df.head(10)

Survived  Pclass  Sex  Age  Fare  Embarked  Title  IsAlone  Age*Class

0         0       3    0    1     0         0      1        0          3

1         1       1    1    2     3         1      3        0          2

2         1       3    1    1     1         0      2        1          3

3         1       1    1    2     3         0      3        0          2

4         0       3    0    2     1         0      1        1          6

5         0       3    0    1     1         2      1        1          3

6         0       1    0    3     3         0      1        1          3

7         0       3    0    0     2         0      4        0          0

8         1       3    1    1     1         0      3        0          3

9         1       2    1    0     2         1      3        0          0

11.建模,预测,并解决问题

现在我们已经做好了训练模型的准备,在模型训练完后,我们即可将其应用到解决问题中。对于预测的问题,我们至少有60多种算法可供选择。

所以我们必须理解问题的类型和解决方案的需求,这样才能缩小模型的选择范围。现在这个问题是一个分类与回归的问题,

我们希望找出输出(即Survived)与其他特征(即Gender,Age,Port等)之间的关系。因为给定了训练集,所以这在机器学习里是一个有监督学习。

所以现在对算法的需求是:有监督学习加上分类与回归。根据这个条件,我们有以下模型可供选择:

  1. Logistic Regression
  2. kNN
  3. SVM
  4. Na?ve Bayes classifier
  5. Decision Tree
  6. Random Forrest
  7. Perceptron
  8. Artificial neural network
  9. RVM or Relevance Vector Machine

现在我们将训练集与测试集再做一下区分:

>>> X_train = train_df.drop(‘Survived‘, axis=1)

>>> Y_train = train_df[‘Survived‘]

>>> X_test = test_df.drop(‘PassengerId‘, axis=1).copy()

>>> X_train, Y_train, X_test

((891, 8), (891,), (418, 8))

Logistic Regression 是一个非常有用的模型,可以在工作流程里优先使用。它通过使用估计概率的方法衡量了离散型特征与其他特征之间的关系,是一个渐增型的逻辑分布。

>>> logreg = LogisticRegression()

>>> logreg.fit(X_train, Y_train)

>>> Y_pred = logreg.predict(X_test)

>>> acc_log = round(logreg.score(X_train, Y_train) * 100, 2)

>>> acc_log

80.359999999999999

我们可以用Logistic Regression来验证我们之间做的假设与结论。这个可以通过计算特征值的系数来达成。正系数可以提升对数几率(所以增长了概率),负系数会降低对数几率(因此降低了概率):

>>> coeff_df = pd.DataFrame(train_df.columns.delete(0))

>>> coeff_df.columns = [‘Feature‘]

>>> coeff_df["Correlation"] = pd.Series(logreg.coef_[0])

>>> coeff_df.sort_values(by=‘Correlation‘, ascending=False)

Feature  Correlation

1        Sex     2.201527

5      Title     0.398234

2        Age     0.287162

4   Embarked     0.261762

6    IsAlone     0.129140

3       Fare    -0.085150

7  Age*Class    -0.311202

0     Pclass    -0.749007

从上面的结果我们可以看出:

  1. Sex是有最高正系数的特征。这个表面当Sex 的值增加时(从male:0到female:1),Survived=1的概率增加最多
  2. 相反的,当Pclass增加时,Survived=1的概率减少最多
  3. 从结果来看,我们创建的新特征Age*Class非常有用,因为它与Survived的负相关性是第二高的
  4. Title是第二高的正系数特征

下一步我们使用SVM来分析数据并做分类与回归分析。

>>> svc = SVC()

>>> svc.fit(X_train, Y_train)

>>> Y_pred = svc.predict(X_test)

>>> acc_svc = round(svc.score(X_train, Y_train) * 100, 2)

>>> acc_svc

83.840000000000003

可以看到使用SVM后的正确率得到了提升。

在模式识别中,KNN算法是一种非参数的方法,用于做分类与回归。使用KNN来分析此问题的话:

>>> knn = KNeighborsClassifier(n_neighbors = 3)

>>> knn.fit(X_train, Y_train)

>>> Y_pred = knn.predict(X_test)

>>> acc_knn = round(knn.score(X_train, Y_train) * 100, 2)

84.739999999999995

可以看到使用KNN的正确率比Logistic Regression更高,但是比SVM更低

下面我们试试朴素贝叶斯:

>>> gaussian = GaussianNB()

>>> gaussian.fit(X_train, Y_train)

>>> Y_pred = gaussian.predict(X_test)

>>> acc_gaussian = round(gaussian.score(X_train, Y_train) * 100, 2)

72.280000000000001

看来在这个问题中使用朴素贝叶斯不是一个很好的选择,从当前来看,它的正确率是最低的。

接下来我们试试 perceptron(感知机)算法,它可以用于二分类问题:

>>> perceptron = Perceptron()

>>> perceptron.fit(X_train, Y_train)

>>> Y_pred = perceptron.predict(X_test)

>>> acc_perceptron = round(perceptron.score(X_train, Y_train) * 100, 2)

78.0

可以看到perceptron的正确率也不高

接下来试试Linear SVC:

>>> linear_svc = LinearSVC()

>>> linear_svc.fit(X_train, Y_train)

>>> Y_pred = linear_svc.predict(X_test)

>>> acc_linear_svc = round(linear_svc.score(X_train, Y_train) * 100, 2)

79.010000000000005

与随机梯度下降分类器:

>>> sgd = SGDClassifier()

>>> sgd.fit(X_train, Y_train)

>>> Y_pred = sgd.predict(X_test)

>>> acc_sgd = round(sgd.score(X_train, Y_train) * 100, 2)

78.230000000000004

这几个算法计算到的正确率都不够理想。

接下来我们看看很常见的决策树算法:

>>> decision_tree = DecisionTreeClassifier()

>>> decision_tree.fit(X_train, Y_train)

>>> Y_pred = decision_tree.predict(X_test)

>>> acc_decision_tree = round(decision_tree.score(X_train, Y_train) * 100, 2)

86.760000000000005

可以看到,使用决策树的算法使得正确率达到了一个更高的值。在目前为止,它的正确率是最高的。

然后我们看看随机森林,随机森林通过组合多个决策树算法来完成:

>>> random_forest = RandomForestClassifier(n_estimators=100)

>>> random_forest.fit(X_train, Y_train)

>>> Y_pred = random_forest.predict(X_test)

>>> acc_random_forest = round(random_forest.score(X_train, Y_train) * 100, 2)

86.760000000000005

通过比较模型的正确率,我们决定使用最高正确率的模型,即随机森林的输出作为结果提交。

12.模型评价

现在我们可以对以上的模型的正确率进行排名,并从中选择一个正确率最高的模型:

models = pd.DataFrame({

‘Model‘: [‘Support Vector Machines‘, ‘KNN‘, ‘Logistic Regression‘,

‘Random Forest‘, ‘Naive Bayes‘, ‘Perceptron‘,

‘Stochastic Gradient Decent‘, ‘Linear SVC‘,

‘Decision Tree‘],

‘Score‘: [acc_svc, acc_knn, acc_log,

acc_random_forest, acc_gaussian, acc_perceptron,

acc_sgd, acc_linear_svc, acc_decision_tree]})

>>> models.sort_values(by=‘Score‘, ascending=False)

Model  Score

3               Random Forest  86.76

8               Decision Tree  86.76

1                         KNN  84.74

0     Support Vector Machines  83.84

2         Logistic Regression  80.36

7                  Linear SVC  79.01

6  Stochastic Gradient Decent  78.23

5                  Perceptron  78.00

4                 Naive Bayes  72.28

其中决策树与随机森林的正确率最高,但是我们在这里会选择随机森林算法,因为它相对于决策树来说,弥补了决策树有可能过拟合的问题。

最后我们做提交:

>>> submission = pd.DataFrame({"PassengerId": test_df["PassengerId"], "Survived": Y_pred})

原文地址:https://www.cnblogs.com/zackstang/p/8185531.html

时间: 2024-10-08 15:00:56

Kaggle泰坦尼克数据科学解决方案的相关文章

利用python进行泰坦尼克生存预测——数据探索分析

最近一直断断续续的做这个泰坦尼克生存预测模型的练习,这个kaggle的竞赛题,网上有很多人都分享过,而且都很成熟,也有些写的非常详细,我主要是在牛人们的基础上,按照数据挖掘流程梳理思路,然后通过练习每一步来熟悉应用python进行数据挖掘的方式. 数据挖掘的一般过程是:数据预览-->数据预处理(缺失值.离散值等)-->变量转换(构造新的衍生变量)-->数据探索(提取特征)-->训练-->调优-->验证 1 数据预览 1.1 head() 预览数据集的前面几条数据可以大致

小丸子踏入python之路:python_day05(用Pandas处理泰坦尼克船员获救数据titanic_train.csv)

泰坦尼克船员获救数据: titanic_train.csv 用excel打开数据集.显示如下: 写在前边: 为了方便以后运用numpy和pandas的库,分别造它们的别名np和pd. import pandas as pd #造pandas的别名为pd import numpy as np #造numpy的别名为np 一.读取数据 import pandas as pd #造pandas的别名为pd import numpy as np #造numpy的别名为np #泰坦尼克号船员获救数据 ti

干货 | 从菜鸟到老司机_数据科学的 17 个必用数据集推荐

原文链接 摘要: ◆ ◆ ◆ 菜鸟入门 1. Iris 数据集 在模式识别文献中,Iris 数据集恐怕是最通用也是最简单的数据集了.要学习分类技术,Iris 数据集绝对是最方便的途径.如果你之前从未接触过数据科学这一概念,从这里开始一定没错,因为该数据集只有 4 列 150 行. ◆ ◆ ◆ 菜鸟入门 1. Iris 数据集 在模式识别文献中,Iris 数据集恐怕是最通用也是最简单的数据集了.要学习分类技术,Iris 数据集绝对是最方便的途径.如果你之前从未接触过数据科学这一概念,从这里开始一定

利用KNIME建立Spark Machine learning模型 2:泰坦尼克幸存预测

本文利用KNIME基于Spark决策树模型算法,通过对泰坦尼克的包含乘客及船员的特征属性的训练数据集进行训练,得出决策树幸存模型,并利用测试数据集对模型进行测试. 1.从Kaggle网站下载训练数据集和测试数据集 2.在KNIME创建新的Workflow,起名:TitanicKNIMESpark 3. 读取训练数据集 KNIME支持从Hadoop集群读取数据,本文为了简化流程直接从本地读取数据集. 在Node Repository的搜索框里输入CSV Reader,找到CSV Reader节点,

大数据科学新发展展望:不得不知的四大趋势

从2012年开始,几乎人人(至少是互联网界)言必称大数据,似乎不和大数据沾点边都不好意思和别人聊天.从2016年开始,大数据系统逐步开始在企业中进入部署阶段,大数据的炒作逐渐散去,随之而来的是应用的蓬勃发展期,一些代表成熟技术的标志性IPO在国内外资本市场也不断出现.转眼间,大数据几年前经历的泡沫正在无可争议地转移到人工智能身上.可以说,在过去的一年,AI所经历的共同意识"大爆炸"与当年的大数据相比,有过之而无不及.最近风口又转移到区块链上了,某种程度上也成为业内人士焦虑的一种诱因了.

黑客来势汹汹,数据科学能拯救社交媒体吗?

不受约束的互联网通常用于黑客恶意目的,而且往往是不准确的,难以追查的.对于社交媒体,尤其是Facebook在保护用户隐私和阻止不法分子播种方面失败了.近日Facebook创始人马克扎克伯格表示将黑客目标锁定: 澳大利亚Anonymous匿名者黑客组织和中国东方联盟Eastunion黑客组织,但也不排除美国本土黑客组织所为,他说,现在不是追查的问题,而是尽快修补这个漏洞,挽回失去的用户. 这就是CEO马克扎克伯格的原因被迫在国会两院之前就用户隐私作证.而现在Facebook和其他社交媒体的政府监管

20本机器学习与数据科学必读书籍

高校的暑假即将来临,有没有想利用这个暑假为自己充电,为未来的自己赢在起跑线上,成为人工智能界的人生赢家呢?来自 KDnuggets 的 Matthew Mayo 就提供了这份书单,小编在翻译此书单的同时,还贴心搜索了相应的中文译本,并提供了中文版的购买链接.加油吧,骚年! 如果你想了解大数据的学习路线,想学习大数据知识以及需要免费的学习资料可以加群:784789432.欢迎你的加入.每天下午三点开直播分享基础知识,晚上20:00都会开直播给大家分享大数据项目实战. 1. <统计思维:程序员数学之

想从事数据科学相关岗位,这些数学基础“必备”

很多同学想从事数据科学岗位,对于这个岗位而言,数学知识的储备重要吗? 答案显而易见,掌握好数学对于从事该岗位而言是很重要的.数学一直是任何当代科学学科的基础,几乎所有的现代数据科学技术(包括所有的机器学习)都有一些深刻的数学知识.在本文中,我们将讨论想成为一名优秀的数据科学家应该掌握的基本数学知识,以便在各个方面都能很好地适应. 介绍 有时候,作为一名数据科学家(甚至是团队的初级分析师),你必须全心全意地学习那些基础的数学知识,或者正确地应用这些技术,有时候你可以通过使用一些API或者拿来即用的

2018年排名前20的数据科学Python库

Python 在解决数据科学任务和挑战方面继续处于领先地位.业已证明最有帮助的Python库,我们选择 20 多个库,因为其中一些库是相互替代的,可以解决相同的问题.因此,我们将它们放在同一个分组. 核心库和统计数据 1. NumPy (提交:17911,撰稿人:641) 官网:http://www.numpy.org/ NumPy 是科学应用程序库的主要软件包之一,用于处理大型多维数组和矩阵,它大量的高级数学函数集合和实现方法使得这些对象执行操作成为可能. 2. SciPy (提交:19150