1. 程式人生 > >機器學習kaggle實戰-泰坦尼克號問題知識梳理

機器學習kaggle實戰-泰坦尼克號問題知識梳理

工作流程:

在資料科學競賽的解決問題的七個步驟:

1.問題或問題的定義。(理解題目)
2.獲得培訓和測試資料。(獲取資料)
3.爭論,準備清理資料。(初步清洗資料)
4.分析、識別模式,並探索資料。(特徵工程)
5.模型,預測和解決問題。(機器學習演算法介入)
6.視覺化報告,並提出解決問題的步驟和最終的解決方案。(調參、優化)

7.供應或提交結果。

涉及相關演算法:

線性迴歸、邏輯迴歸、隨機森林、模型融合。

問題回顧:

1912年4月15日,在首次航行期間,泰坦尼克號撞上冰山後沉沒,2224名乘客和機組人員中有1502人遇難。翻譯成32%的存活率。
海難導致生命損失的原因之一是沒有足夠的救生艇給乘客和機組人員。
雖然倖存下來的運氣有一些因素,但一些人比其他人更有可能生存,比如婦女,兒童和上層階級。

 

資料分析

資料共891行,12列資料,有用特徵11列,還有1個標籤列,其中PassengerId只是資料標號,"Survivrd"特徵是標籤

Survived:是否生存 1表示存活,0表示未生存

1.PassengerId:乘客編號,無用資料

2.Pclass:乘客等級 1/2/3等艙

3.Name:乘客姓名

4.Sex:性別 male:男性,female:女性

5.Age:年齡

6.SibSp:堂兄/妹個數

7.Parch:父母與小孩個數

8.Ticket:船票資訊

9.Fare:票價

10.Cabin:客艙

11.Embarked:登船港口

相關演算法及引數說明:

 

random_state
作為每次產生隨機數的種子
作為隨機種子對於調參過程是很重要的,如果每次都用不同的隨機種子。即使引數值沒變,每次出來的結果也會不同,不利於比較不同模型的結果
任一個隨機樣本都有可能導致過度你和,可以用不同的隨機樣本建模來減少過擬合到的可能


n_estimators
定義了需要用到的決策樹的數量

min_samples_split

定義了書中一個節點所需要用來分裂的最少樣本數,可以避免過擬合,如果用於分類的樣本數太小,模型可能只試用於用來訓練樣本的分類,而用較多的樣本數則可以避免這個問題

如果設定的值過大,就可能出現欠擬合現象,所以可以用cv值(離散數量)考量調節效果
min_samples_leaf
定義了樹中終點節點所需要用來分裂的最少樣本數,同樣可以防止過度擬合
不均等分類問題中,一般這個引數需要設定為較小的值。因為大部分少數類別含有的樣本都比較小
min_weight_fraction_leaf
和上面的min_simples_leaf 很像,不同的是這個引數需要被設定為較小的值,因為大部分少數類別含有的樣本都比較小
max_depth
定義和樹的最大深度,也可以控制過擬合,樹越深,越容易過擬合,也可以用CV值檢驗
max_leaf_nodes
定義了決策樹裡最多能有多少個終點節點,這個屬性可能在上面的max_depth裡就被定義了,深度為n的二叉樹就有最多2的n次方的終點節點
如果定義max_leaf_nodes GBM就會忽略前面的 max_depth
max_features
決定了用於分類的特徵樹,是認為隨機定義的


開始進入正題:python版本3.7

#匯入資料

import pandas as pd
titanic = pd.read_csv('titanic_train.csv')
titanic.head()
print (titanic.describe())

#資料預處理, 填充缺失值以及將特徵中含有字元的轉換為數值型
#將年齡這一列的資料缺失值按均值進行填充
titanic["Age"] = titanic["Age"].fillna(titanic["Age"].median())
print(titanic.describe())

#檢視Sex種類

print(titanic["Sex"].unique())

 

#將性別中的男女設定為0 1 值 把機器學習不能處理的自字元值轉換成能處理的數值
#loc定位到哪一行,將titanic['Sex'] == 'male'的樣本Sex值改為0
titanic.loc[titanic['Sex'] =='male','Sex'] = 0
titanic.loc[titanic['Sex'] =='female','Sex'] = 1

#檢視港口種類,發現有缺失值

print(titanic['Embarked'].unique())

#將登船地點同樣轉換成數值,缺失值用‘S’填充
titanic['Embarked']=titanic['Embarked'].fillna('S')
titanic.loc[titanic['Embarked'] == 'S','Embarked'] = 0
titanic.loc[titanic['Embarked'] == 'C','Embarked'] = 1
titanic.loc[titanic['Embarked'] == 'Q','Embarked'] = 2

 #線性模型

#匯入線性迴歸包

from sklearn.linear_model import LinearRegression
from sklearn.cross_validation import KFold
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
alg = LinearRegression()
#將m個樣本分成三份 n_folds 代表的是交叉驗證劃分幾層(幾份)
kf = KFold(titanic.shape[0], n_folds=3, random_state=1)
predictions = []
for train, test in kf:
#將訓練資料拿出來,對原始資料取到建立好的特徵 然後取出用於訓練的那一部分
train_predictors = (titanic[predictors].iloc[train,:])
train_target = titanic["Survived"].iloc[train]
#進行訓練
alg.fit(train_predictors, train_target)
#用test集對模型進行驗證
test_predictions = alg.predict(titanic[predictors].iloc[test,:])
predictions.append(test_predictions)
import numpy as np
predictions = np.concatenate(predictions, axis=0)
predictions[predictions > .5] = 1
predictions[predictions <=.5] = 0

titanic["Survived"] = titanic["Survived"].astype(float)

print("測試資料總數量",len(predictions))
print("正確的數量:",sum(predictions == titanic["Survived"]))

accuracy = sum(predictions == titanic["Survived"]) / len(predictions)
#準確率
print( accuracy)

 

 #邏輯迴歸模型

#匯入邏輯迴歸包

from sklearn import cross_validation
from sklearn.linear_model import LogisticRegression
alg = LogisticRegression(random_state=1)
#使用邏輯迴歸做交叉驗證3次
scores = cross_validation.cross_val_score(alg,titanic[predictors],titanic['Survived'],cv=3)
print(scores.mean())

可以看出這裡單純的邏輯迴歸的準確率提升不是很明顯

 

測試表做同樣的資料處理

titanic_test = pd.read_csv("test.csv")
titanic_test["Age"] = titanic_test["Age"].fillna(titanic["Age"].median())
titanic_test["Fare"] = titanic_test["Fare"].fillna(titanic_test["Fare"].median())
titanic_test.loc[titanic_test["Sex"] == "male", "Sex"] = 0
titanic_test.loc[titanic_test["Sex"] == "female", "Sex"] = 1
titanic_test["Embarked"] = titanic_test["Embarked"].fillna("S")

titanic_test.loc[titanic_test["Embarked"] == "S", "Embarked"] = 0
titanic_test.loc[titanic_test["Embarked"] == "C", "Embarked"] = 1
titanic_test.loc[titanic_test["Embarked"] == "Q", "Embarked"] = 2

 

#隨機森林模型

from sklearn import cross_validation
from sklearn.ensemble import RandomForestClassifier

#特徵列表

predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
alg = RandomForestClassifier(random_state=1, n_estimators=10, min_samples_split=2, min_samples_leaf=1)
kf = cross_validation.KFold(titanic.shape[0], n_folds=3, random_state=1)
scores = cross_validation.cross_val_score(alg, titanic[predictors], titanic["Survived"], cv=kf)
print(scores.mean())
#因為10顆樹太少,分數提高的不明顯

#對樹進行構造多一點

alg = RandomForestClassifier(random_state=1, n_estimators=25, min_samples_split=4, min_samples_leaf=2)
# Compute the accuracy score for all the cross validation folds. (much simpler than what we did before!)
kf = cross_validation.KFold(titanic.shape[0], 3, random_state=1)
scores = cross_validation.cross_val_score(alg, titanic[predictors], titanic["Survived"], cv=kf)
#交叉驗證3次平均分
print(scores.mean())

#可以看出分數提升了不少

 

#構造特徵,玄學分析名字長度和家庭成員數對獲救的影響
titanic["FamilySize"] = titanic["SibSp"] + titanic["Parch"]

titanic["NameLength"] = titanic["Name"].apply(lambda x: len(x))

import re

#正則表示式提取姓名
def get_title(name):
title_search = re.search(' ([A-Za-z]+)\.', name)
if title_search:
return title_search.group(1)
return ""

#新構建特徵
titles = titanic["Name"].apply(get_title)
print(pd.value_counts(titles))

#將str特徵轉換為數值型別
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 7, "Mlle": 8, "Mme": 8, "Don": 9, "Lady": 10, "Countess": 10, "Jonkheer": 10, "Sir": 9, "Capt": 7, "Ms": 2}
for k,v in title_mapping.items():
titles[titles == k] = v

#列印稱呼特徵總計數
print(pd.value_counts(titles))
#新增新的特徵
titanic["Title"] = titles

 

#對特徵進行畫圖,直方圖顯示特徵權重對最終結果的影響
import numpy as np
from sklearn.feature_selection import SelectKBest, f_classif
import matplotlib.pyplot as plt
#特徵列表
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked", "FamilySize", "Title", "NameLength"]

selector = SelectKBest(f_classif, k=5)
selector.fit(titanic[predictors], titanic["Survived"])

# Get the raw p-values for each feature, and transform from p-values into scores
scores = -np.log10(selector.pvalues_)

# Plot the scores. See how "Pclass", "Sex", "Title", and "Fare" are the best?
plt.bar(range(len(predictors)), scores)
plt.xticks(range(len(predictors)), predictors, rotation='vertical')
plt.show()

#只保留權重大的特徵,並依然只做三次交叉驗證。比較結果發現確實和上面多特徵結果大致無變化。
predictors = ["Pclass", "Sex", "Fare", "Title"]
alg = RandomForestClassifier(random_state=1, n_estimators=25, min_samples_split=4, min_samples_leaf=2)
kf = cross_validation.KFold(titanic.shape[0], n_folds=3, random_state=1)
scores = cross_validation.cross_val_score(alg, titanic[predictors], titanic["Survived"], cv=kf)
print(scores.mean())

 

 

#堆疊演算法(模型融合)

 

#將兩個演算法結合著使用,Boosting和邏輯迴歸結合使用
from sklearn.ensemble import GradientBoostingClassifier
import numpy as np

#GradientBoostingClassifier看成一個森林
algorithms = [
[GradientBoostingClassifier(random_state=1, n_estimators=25, max_depth=3), ["Pclass", "Sex", "Age", "Fare", "Embarked", "FamilySize", "Title",]],
[LogisticRegression(random_state=1), ["Pclass", "Sex", "Fare", "FamilySize", "Title", "Age", "Embarked"]]
]
kf = KFold(titanic.shape[0], n_folds=3, random_state=1)
predictions = []
for train, test in kf:
train_target = titanic["Survived"].iloc[train]
full_test_predictions = []
#對每一個演算法進行驗證
for alg, predictors in algorithms:
#訓練模型
alg.fit(titanic[predictors].iloc[train,:], train_target)
#模型預測,並轉換為float避免預測值失真
test_predictions = alg.predict_proba(titanic[predictors].iloc[test,:].astype(float))[:,1]
full_test_predictions.append(test_predictions)
#對兩種演算法的結果相加求均值作為最終結果
test_predictions = (full_test_predictions[0] + full_test_predictions[1]) / 2
#小於等於0.5則未獲救 大於0.5則獲救
test_predictions[test_predictions <= .5] = 0
test_predictions[test_predictions > .5] = 1
predictions.append(test_predictions)

#將結果轉為一維陣列
predictions = np.concatenate(predictions, axis=0)

#森林引數沒有調優的情況下求出準確率 大約提升了0.08個點
accuracy = sum(predictions == titanic["Survived"]) / len(predictions)
print(accuracy)

#測試表做同樣的特徵工程處理
titles = titanic_test["Name"].apply(get_title)
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 7, "Mlle": 8, "Mme": 8, "Don": 9, "Lady": 10, "Countess": 10, "Jonkheer": 10, "Sir": 9, "Capt": 7, "Ms": 2, "Dona": 10}
for k,v in title_mapping.items():
titles[titles == k] = v
titanic_test["Title"] = titles
print(pd.value_counts(titanic_test["Title"]))
titanic_test["FamilySize"] = titanic_test["SibSp"] + titanic_test["Parch"]

 

#終極預測方案

predictors = ["Pclass", "Sex", "Age", "Fare", "Embarked", "FamilySize", "Title"]

algorithms = [
[GradientBoostingClassifier(random_state=1, n_estimators=25, max_depth=3), predictors],
[LogisticRegression(random_state=1), ["Pclass", "Sex", "Fare", "FamilySize", "Title", "Age", "Embarked"]]
]
#用堆疊演算法對測試表進行預測
full_predictions = []
for alg, predictors in algorithms:
alg.fit(titanic[predictors], titanic["Survived"])
predictions = alg.predict_proba(titanic_test[predictors].astype(float))[:,1]
full_predictions.append(predictions)

#隨機森林3倍權重+邏輯迴歸結果均值作為最終預測值
predictions = (full_predictions[0] * 3 + full_predictions[1]) / 4
predictions