Kaggle泰坦尼克-Python(建模完整流程,小白學習用)

參考Kernels裏面評論較高的一篇文章,整理做者解決整個問題的過程,梳理該篇是用以瞭解到整個完整的建模過程,如何思考問題,處理問題,過程當中又爲什麼下那樣或者這樣的結論等!html

最後得分並非特別高,只是到34%,更可能是整理一個解決問題的思路,另外前面三個大步驟根據思惟導圖看便可,代碼跟文字等從第四個步驟開始寫起。python

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------正則表達式

(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)獲取數據:app

咱們能夠用python 的 Pandas 來幫助咱們處理數據。首先能夠將訓練數據以及測試數據讀入到Pandas 的 DataFrames 裏。咱們也會將這兩個數據集結合起來,用於在兩個數據集上同時作一些特定的操做。less

# 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) 經過描述數據來分析:dom

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.

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

查看訓練集裏面各字段:

print(train_df.columns.values)
['PassengerId' 'Survived' 'Pclass' 'Name' 'Sex' 'Age' 'SibSp' 'Parch'

 'Ticket' 'Fare' 'Cabin' 'Embarked']

PassengerId => 乘客ID

Pclass => 乘客等級(1/2/3等艙位)

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的特徵可能包含錯誤或者打字錯誤,由於會有好幾種方法來描述名字

#默認倒數5行
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()

test_df.info()

8. 在樣本里,數值型特徵的數值分佈是什麼樣的?

這個能夠幫助咱們初步瞭解:訓練數據集如何體現了實際問題。

在這個問題中:

  1. 一共有891個樣本
  2. Survived的標籤是經過0或1來區分
  3. 大概38%的樣本是survived
  4. 大多數乘客(>76%)沒有與父母或是孩子一塊兒旅行
  5. 大約30%的乘客有親屬和/或配偶一塊兒登船
  6. 票價的差異很是大,少許的乘客(<1%)付了高達$512的費用
  7. 不多的乘客(<1%)年紀在64-80之間

咱們能夠經過如下方式獲取上述信息:

train_df.describe()

# 經過使用 percentiles=[.61, .62] 來查看數據集能夠了解到生存率爲 38%
train_df.describe(percentiles=[.61, .62])

# 經過使用 percentiles=[.76, .77] 來查看Parch的分佈
train_df.describe(percentiles=[.76, .77])

# 經過使用 percentile=[.68, .69] 來查看SibSp的分佈
train_df.describe(percentiles=[.68, .69])

#經過使用 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])

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'])

 

(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 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)

 

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

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

 

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

(9)經過將數據可視化進行分析

如今咱們能夠經過將數據可視化對數據作進一步分析,並繼續驗證咱們以前的假設是否正確

 

數值型特徵與Survived之間的聯繫:

柱狀圖在用於分析連續型的數值特徵時很是有用,如特徵Age,它的柱狀圖數值範圍(不一樣的年齡範圍)能夠幫助咱們識別一些有用的模式。

經過使用默認或自定的數值範圍(年齡範圍),柱狀圖能夠幫助咱們描繪出樣本所遵循的分佈。

它能夠幫助咱們發現是否某些特定的年齡範圍(如嬰兒)有更高的存活率。

 

咱們能夠經過如下代碼來畫出Age的柱狀圖:

g = sns.FacetGrid(train_df, col='Survived')
g.map(plt.hist, 'Age', bins=20)
plt.show()

觀察:

  1. 嬰兒(Age<=4)有較高的生存率(20個bin,每一個bin爲4歲)
  2. 老人(Age=80)所有生還
  3. 大量的15-25年紀的乘客沒有生還
  4. 乘客主要在15-35的年紀範圍內

結論:

以上簡單的分析驗證了咱們以前的假設:

  1. 咱們須要將Age考慮到訓練模型裏
  2. 爲Age特徵補全null
  3. 咱們應該劃分不一樣的年齡層

 

數值型與序列型特徵之間的聯繫:

咱們能夠將多個特徵組合,而後經過一個簡單的圖來識別它們之間的關係。這種方法能夠應用在數值型以及分類型(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. Pclass=2和Pclass=3中,大多數嬰兒活了下來,進一步驗證了咱們以前在「分類」裏的假設 
  3. 大多數Pclass=1的乘客存活,驗證咱們以前在「分類」裏的假設
  4. 不一樣Pclass中Age的分佈不一樣

結論:

  考慮將Pclass特徵加入模型訓練

 

離散型特徵與Survived之間的聯繫:

如今咱們能夠查看離散型特徵與survived之間的關係

 咱們能夠經過如下方式將數據可視化:

grid = sns.FacetGrid(train_df, row='Embarked', size=2.2, aspect=1.6)
grid.map(sns.pointplot, 'Pclass', 'Survived', 'Sex',order=[1,2,3],hue_order=train_df.Sex.unique(),palette='deep')
grid.add_legend()
plt.show()
#原做者代碼沒有加入order、hue_order所以圖示會有錯誤,並得出了錯誤的結論,不過那個結論沒有應用到後續的特徵選擇。。建議代碼完成後結果可執行可是會提示有可能引發錯誤提示的話,仍是修改下代碼比較好

觀察:

  1. 女性乘客相對於男性乘客有着更高的存活率
  2. Embarked和Survived之間可能並無直接的聯繫。 
  3. 對於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', order=train_df.Sex.unique(),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)

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)

 

經過已有的特徵建立新特徵:

咱們在丟棄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'])
#西方姓名中間會加入稱呼,好比小男童會在名字中間加入Master,女性根據年齡段及婚姻情況不一樣也會使用Miss 或 Mrs 等,這算是基於業務的理解作的衍生特徵,原做者應該是考慮能夠用做區分人的特徵所以在此嘗試清洗數據後加入

咱們可使用高一些更常見的名字或「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轉換爲有序的數值型:

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

train_df.head()

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

 

新的發現:

當咱們畫出Title,Age和Survived的圖後,咱們有了如下新的發現:

  1. 大多數Title分段與年齡字段對應準確,好比,Title爲Master平均年齡爲5歲
  2. 不一樣組別Title與生產率有必定的區分度。
  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()

 

補全連續數值型特徵

如今咱們能夠開始爲那些含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()

 如今咱們對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)

而後咱們根據上面的分段,使用有序的數值來替換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()

接着咱們能夠丟棄AgeBand特徵:

train_df = train_df.drop(['AgeBand'], axis=1)
combine = [train_df, test_df]
train_df.head()

 

經過已有的特徵組合出新特徵

如今咱們能夠經過組合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)

接着咱們能夠建立另外一個名爲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()

基於上面的數據表現,咱們如今能夠丟棄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()

for dataset in combine:
    dataset['Age*Class'] = dataset.Age * dataset.Pclass

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

 

補全一個離散型的特徵

Embarked特徵主要有三個值,分別爲S,Q,C,對應了三個登船港口。在訓練集裏,這個有2個缺失值,咱們會使用頻率最高的值來填充這個缺失值。

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

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特徵轉換爲數值型特徵

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

train_df.head()

補全數值型特徵

如今咱們能夠開始爲測試集裏的Fare特徵補全數據。在補全時,咱們可使用最頻繁出現的數據用於補全缺失值。

(咱們也能夠將Fare的數值作四捨五入,將它精確到2位)

test_df['Fare'].fillna(test_df['Fare'].dropna().median(), inplace=True)
test_df.head()

接下來咱們將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,將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與其餘特徵之間的相關性

corrmat = train_df.corr()

k = 10
cols = corrmat.nlargest(k,'Survived')['Survived'].index  #取出與Survived相關性最大的十項
cm = np.corrcoef(train_df[cols].values.T)  #相關係數 
sns.set(font_scale = 1.25)
hm = sns.heatmap(cm,cbar = True,annot = True,square = True ,fmt = '.2f',annot_kws = {'size': 10},yticklabels = cols.values,xticklabels = cols.values)
plt.show()

 

(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.shape, Y_train.shape, X_test.shape

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.36

咱們能夠用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)

從上面的結果咱們能夠看出:

  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.84

能夠看到使用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)
acc_knn

#84.74

能夠看到使用KNN的正確率比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)
acc_gaussian

#72.28

看來在這個問題中使用樸素貝葉斯不是一個很好的選擇,從當前來看,它的正確率是最低的。

 

接下來咱們試試 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)
acc_perceptron

#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)
acc_linear_svc

#79.01

 

與隨機梯度降低分類器:

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)
acc_sgd

#69.92

 

接下來咱們看看很常見的決策樹算法:

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)
acc_decision_tree

#86.76

能夠看到,使用決策樹的算法使得正確率達到了一個更高的值。在目前爲止,它的正確率是最高的。

 

而後咱們看看隨機森林,隨機森林經過組合多個決策樹算法來完成:

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)
acc_random_forest

#86.76

經過比較模型的正確率,咱們決定使用最高正確率的模型,即隨機森林的輸出做爲結果提交。

 

(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)

其中決策樹與隨機森林的正確率最高,可是咱們在這裏會選擇隨機森林算法,由於它相對於決策樹來講,彌補了決策樹有可能過擬合的問題。

 

最後咱們作提交:

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

 

參考博文

http://www.cnblogs.com/zackstang/p/8185531.html

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息