kaggle項(xiàng)目之Titanic數(shù)據(jù)集

本例主要針對(duì)kaggle上的Titanic數(shù)據(jù)集進(jìn)行分析預(yù)測(cè),文章主體分為以下兩個(gè)部分:

  • 機(jī)器學(xué)習(xí)流程的回顧
  • Titanic數(shù)據(jù)集的分析和處理
    image

    PS:流程回顧來源于Udacity的機(jī)器學(xué)習(xí)入門課程,Titanic數(shù)據(jù)的處理參考了kaggle上眾位大佬的分享。
    ——————流程回顧——————

在開始進(jìn)行分析之前,讓我們仔細(xì)回顧下一個(gè)機(jī)器學(xué)習(xí)項(xiàng)目的流程。

數(shù)據(jù)集/問題——>特征處理——>算法建?!?gt;評(píng)估

第一步,數(shù)據(jù)集/問題

機(jī)器學(xué)習(xí)是用來解決實(shí)際問題的,收集與實(shí)際問題有關(guān)的數(shù)據(jù),能夠有助于后續(xù)步驟的繼續(xù)進(jìn)行。在這個(gè)階段需要知道

  • 數(shù)據(jù)量足夠大?
  • 我提出了什么問題?
  • 要回答這個(gè)問題,有足夠的正確的特征么?
第二步,特征處理
  • 探索型分析(EDA)
    分析特征與變量的相關(guān)性(pearsonr相關(guān)系數(shù))
    刪除一些離群值
    清理特征與數(shù)據(jù)

  • 生成新的特征
    一般來說,基于對(duì)現(xiàn)實(shí)業(yè)務(wù)的了解,生成新的特征。

  • 特征選擇

    • 單變量特征選擇工具:
      SelectPercentile :最強(qiáng)大的 X% 特征(X 是參數(shù))
      SelectKBest :選擇 K 個(gè)最強(qiáng)大的特征(K 是參數(shù))
    • 迭代特征(增/減)
    • lasso回歸:
      在最小誤差與特征數(shù)量之間尋找一個(gè)平衡,實(shí)際應(yīng)用中,該數(shù)值越接近0,說明該特征帶來的影響也就越小。
    • 刪除不必要的特征
  • 特征的縮放(適用于維度變化的算法):
    減去平均值:x - mean
    minmax scaler:(x-min)/(max-min)
    standard scaler:(x-mean)/sigma

  • 轉(zhuǎn)換特征:

    • PCA(主成分分析):數(shù)據(jù)中使方差最大化的方向,在對(duì)這些成分壓縮或投影時(shí),將信息丟失的可能性降至最低。
      【只對(duì)符合高斯分布的樣本點(diǎn)有效】
      一般用于轉(zhuǎn)換成新的特征,也可以用來劃分等級(jí),方差最大為第一等級(jí),以此類推,但第一主成分絕對(duì)不會(huì)與第二主成分疊加。主成分等級(jí)的數(shù)量是有上限的,受制于輸入特征的數(shù)量。

      用處:

      • 尋找隱藏特征
      • 降維:可視化高維數(shù)據(jù),減噪
    • ICA(獨(dú)立成分分析)

    • FA(因子分析)

第三步,算法

根據(jù)是否需要labels,分為監(jiān)督學(xué)習(xí)和非監(jiān)督學(xué)習(xí)

  • 監(jiān)督學(xué)習(xí):
    • 回歸:線性回歸、lasso回歸、決策樹回歸、sv回歸
    • 分類:決策樹、樸素貝葉斯、SVM、隨機(jī)森林、Adaboost、knn、LDA、logistic回歸
  • 非監(jiān)督學(xué)習(xí):
    • 聚類:K均值、DBSCN、EM算法、離群值檢測(cè)
  • 運(yùn)行算法:調(diào)參、可視化檢驗(yàn)、在測(cè)試集上運(yùn)行、尋找最佳參數(shù)(GridsearchCV)
第四步,評(píng)估
  • 驗(yàn)證:
    分隔測(cè)試集和訓(xùn)練集、k-flods法、可視化
  • 評(píng)估指標(biāo)
    SSE/R^2、準(zhǔn)確率、召回率、F1 分?jǐn)?shù)、特征曲線

PS:
以上步驟的順序不是絕對(duì)的,為了獲得擁有強(qiáng)大泛化能力的模型,我們需要不斷地重復(fù)某些步驟。

———————Titanic數(shù)據(jù)集的分析與預(yù)測(cè)——————

n久之前,初生不畏牛犢的我,進(jìn)入了kaggel,第一個(gè)練手的數(shù)據(jù)集——Titanic,死得劇慘。重新整理了思路了之后,預(yù)測(cè)效果也好了很多,具體思路見下文。

主要思路

  1. 加載數(shù)據(jù)集并進(jìn)行簡(jiǎn)要探索性分析
  2. 特征工程
  3. 建模與模型評(píng)估

以前分析思路:
加載數(shù)據(jù)集——數(shù)據(jù)清理——探索性分析——特征處理——建模評(píng)估

1. 加載數(shù)據(jù)集&探索性分析

(1)數(shù)據(jù)概覽:

train:


頭幾行數(shù)據(jù)

數(shù)據(jù)類型與空值狀況

數(shù)據(jù)分布的整體狀況

從簡(jiǎn)要的概覽中,可以看出訓(xùn)練集中存在這些情況:

  • Age,Cabin,Embarked存在空值
  • Age,SibSp,Parch,Fare分布似乎呈偏右分布,具體還需要驗(yàn)證

測(cè)試集的加載和訓(xùn)練集類似,可以自己去試下。
這里為方便處理,合并訓(xùn)練集和測(cè)試集,生成新的DataFrame.

#合并測(cè)試集和訓(xùn)練集
df =  pd.concat([train, test], axis=0).reset_index()
(2)從分布來看:

a. 整體的生存狀況


image

b. SeX


image

c. Pclass
image

image

d. Embarked


image

e. Age
image

f. Fare
image

g. Parch
image

h. SibSp
image

發(fā)現(xiàn):

  • 女性的存活率高于男性
  • Pclass1,2,3的生存率依次降低,這有可能與不同層的乘船人的社會(huì)地位,富裕程度有關(guān)
  • Pclass 1,2女性的生存率遠(yuǎn)大于Pclass 3的女性,Pclass 1 的男性的生存率大于Pclass 2,3層的男性
  • S口岸登船的人數(shù)最多,生存率也最低,C、Q口岸登船的人數(shù)和生存率正好相反。那個(gè)時(shí)代,遠(yuǎn)沒有現(xiàn)在網(wǎng)絡(luò)時(shí)代的發(fā)達(dá),所以我們可以假定認(rèn)為一個(gè)口岸登船的同一層的很容易坐在一起的,這也很可能是一個(gè)影響逃生率的因素。
  • 年齡上來說,似乎很統(tǒng)一,小孩先走,存活率較高
  • Fare分布差異很大,可能存在幼童免票,團(tuán)體票,家庭票等情況
  • Parch 代表同船的父母或子女,SipSp代表同船的兄弟姐妹,這都是兩個(gè)表現(xiàn)親人的關(guān)系,后面一起會(huì)做特征處理。
  • 單人的存活幾率低于有1個(gè)以上的或3個(gè)以下的親人同船的存活幾率,但過于一些過于龐大的家庭成員的生存幾率。家庭成員過多也不好,過少也不好。

2. 特征工程

(1)Embarked
#缺失值填充
df['Embarked'].fillna("S",inplace=True)
#數(shù)值化S,C,Q
le = LabelEncoder()
le.fit(df['Embarked'])
df['Embarked'] = le.transform(df['Embarked'])
(2)Fare
#分配到個(gè)人票價(jià)
df['Fare'] = df['Fare'] / df.groupby('Ticket')['Fare'].transform('count')
df['Fare'].fillna(df['Fare'].median(),inplace=True)
sns.distplot(df["Fare"])
plt.title("Distribution of Fare");
image
#定義一個(gè)票價(jià)分級(jí)函數(shù)
def fare_level(s):
    if s <= 5 :
        m = 0
    elif s>5 and s<=20:
        m = 1
    elif s>20 and s<=40:
        m = 2
    else:
        m = 3
    return m
df['Fare_level'] = df['Fare'].apply(fare_level)
(3)Parch and SibSp
#組合Parch,SibSp
df['Family_memebers'] = df['Parch'] + df['SibSp'] + 1
(4)Sex
#數(shù)值化性別
le.fit(df['Sex'])
df['Sex'] = le.transform(df['Sex'])
(5)Age

年齡擁有大量的缺失值,處理方法有很多中,這里采用建立一個(gè)回歸模型預(yù)測(cè)年齡缺失值。

#利用線性回歸和隨機(jī)森林回歸模型預(yù)測(cè)Age的值
age_nan = pd.DataFrame(df[['Age', 'Sex','Family_memebers', 'Fare',  'Pclass', 'Embarked']])
age_train = age_nan[age_nan.Age.notnull()]
age_test = age_nan[age_nan.Age.isnull()]
#線性回歸
lr = LinearRegression()
lr_grid_pattern = {'fit_intercept': [True], 'normalize': [True]}
lr_grid = GridSearchCV(lr, lr_grid_pattern, cv=10, n_jobs=25, verbose=1, scoring='neg_mean_squared_error')
lr_grid.fit(age_train.drop("Age",axis=1), age_train["Age"])
print('Age feature Best LR Params:' + str(lr_grid.best_params_))
print('Age feature Best LR Score:' + str(lr_grid.best_score_))
lr = lr_grid.predict(age_test.drop("Age",axis=1))
#隨機(jī)森林回歸
rfr = RandomForestRegressor()
rfr_grid_pattern = {'max_depth': [3], 'max_features': [3]}
rfr_grid = GridSearchCV(rfr, rfr_grid_pattern, cv=10, n_jobs=25, verbose=1, scoring='neg_mean_squared_error')
rfr_grid.fit(age_train.drop("Age",axis=1), age_train["Age"])
print('Age feature Best LR Params:' + str(rfr_grid.best_params_))
print('Age feature Best LR Score:' + str(rfr_grid.best_score_))
rfr = rfr_grid.predict(age_test.drop("Age",axis=1))
#取二者均值
age_test["Age"] = (lr+rfr)/2
#定義年齡分級(jí)的函數(shù)
def age_level(s):
    if s <= 15 :      #兒童
        m = 0      
    elif s>15 and s<=30: #青年及少年
        m = 1
    elif s>30 and s<=60: #壯年
        m = 2
    else:               #老年
        m = 3
    return m
df["Age_level"] = df["Age"].apply(age_level)

3. 建模與模型評(píng)估

X = df[:len(train)][['Age_level', 'Sex','Family_memebers', 'Fare_level',  'Pclass', 'Embarked']]
y = df[:len(train)]["Survived"]
(1)評(píng)估方法
  • 混淆矩陣
    有準(zhǔn)確率、召回率、F1值等指標(biāo),本文采用準(zhǔn)確率。
  • 交叉檢驗(yàn)
    將數(shù)據(jù)集劃分成n份,選擇一份作為測(cè)試集,其余n-1份作為訓(xùn)練集,重復(fù)n次(每次的測(cè)試集都不同)。
(2)建模

利用交叉檢驗(yàn)得到結(jié)果,cv = 10,指標(biāo)為準(zhǔn)確率,可以看到SVC具有出色的表現(xiàn)。


image
(3)模型優(yōu)化

主要利用GridSearchCV尋找最佳擬合的結(jié)果。

SVMC = SVC(probability=True)
svc_param_grid = {'kernel': ['rbf'], 
                  'gamma': [ 0.001, 0.01, 0.1, 1],
                  'C': [1, 10, 50, 100,200,300, 1000]}

gsSVMC = GridSearchCV(SVMC,param_grid = svc_param_grid, cv=10, scoring="accuracy", n_jobs= 4, verbose = 1)

gsSVMC.fit(X,y)
SVMC_best = gsSVMC.best_estimator_
(4)預(yù)測(cè)
features = ['Age_level', 'Sex','Family_memebers', 'Fare_level',  'Pclass', 'Embarked']

SVMC_best.fit(X,y)

out_text = SVMC_best.predict(df[len(train):][features])
text = pd.DataFrame(out_text.astype(int),index=df[len(train):]['PassengerId'].values).reset_index() 
text.rename(columns={"index":"PassengerId",0:"Survived"}).to_csv('predict_02.csv',index=False)

最后的結(jié)果:


image

筆者終于從倒數(shù)爬到了正數(shù),不容易。
總體上來看,

  • Titanic的特征數(shù)量比較少,很容易入手
  • 后來我又用VotingClassifier進(jìn)行集成,但結(jié)果居然沒有單獨(dú)的SVC表現(xiàn)更好,這可能與其強(qiáng)大隨機(jī)性有關(guān),具體的原因還可以再探究一下。
  • 就特征方面來說,name和ticket可能包含了同一家人的信息,筆者沒有做具體分析,這塊可以再繼續(xù)深入。

原文代碼:在這里

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容