99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁精彩閱讀揭秘丨備戰(zhàn)CDA數(shù)據(jù)分析競賽!
揭秘丨備戰(zhàn)CDA數(shù)據(jù)分析競賽!
2017-01-16
收藏

 Kaggle是一個數(shù)據(jù)分析建模的應(yīng)用競賽平臺,有點類似KDD-CUP(國際知識發(fā)現(xiàn)和數(shù)據(jù)挖掘競賽),企業(yè)或者研究者可以將問題背景、數(shù)據(jù)、期望指標(biāo)等發(fā)布到Kaggle上,以競賽的形式向廣大的數(shù)據(jù)科學(xué)家征集解決方案。而熱愛數(shù)(dong)據(jù)(shou)挖(zhe)掘(teng)的小伙伴們可以下載/分析數(shù)據(jù),使用統(tǒng)計/機器學(xué)習(xí)/數(shù)據(jù)挖掘等知識,建立算法模型,得出結(jié)果并提交,排名top的可能會有獎金!


01 關(guān)于泰坦尼克號之災(zāi)

· 帶大家去該問題頁面溜達一圈吧

· 下面是問題背景頁 


· 泰坦尼克號問題之背景

· 就是那個大家都熟悉的『Jack and Rose』的故事,豪華游艇倒了,大家都驚恐逃生,可是救生艇的數(shù)量有限,無法人人都有,副船長發(fā)話了『lady and kid first!』,所以是否獲救其實并非隨機,而是基于一些背景有rank先后的。

· 訓(xùn)練和測試數(shù)據(jù)是一些乘客的個人信息以及存活狀況,要嘗試根據(jù)它生成合適的模型并預(yù)測其他人的存活狀況。

· 對,這是一個二分類問題,是我們之前討論的logistic regression所能處理的范疇。

02 說明

接觸過Kaggle的同學(xué)們可能知道這個問題,也可能知道RandomForest和SVM等等算法,甚至還對多個模型做過融合,取得過非常好的結(jié)果,那maybe這篇文章并不是針對你的,你可以自行略過。

我們因為之前只介紹了Logistic Regression這一種分類算法。所以本次的問題解決過程和優(yōu)化思路,都集中在這種算法上。

03 初探數(shù)據(jù)

先看看我們的數(shù)據(jù),長什么樣吧。在Data下我們train.csv和test.csv兩個文件,分別存著官方給的訓(xùn)練和測試數(shù)據(jù)。

import pandas as pd #數(shù)據(jù)分析

import numpy as np #科學(xué)計算

from pandas import Series,DataFrame

data_train = pd.read_csv("/Users/Hanxiaoyang/Titanic_data/Train.csv")
data_train

pandas是常用的python數(shù)據(jù)處理包,把csv文件讀入成dataframe各式,我們在ipython notebook中,看到data_train如下所示:


這就是典型的dataframe格式,如果你沒接觸過這種格式,完全沒有關(guān)系,你就把它想象成Excel里面的列好了。 

我們看到,總共有12列,其中Survived字段表示的是該乘客是否獲救,其余都是乘客的個人信息,包括:

· PassengerId => 乘客ID
· Pclass => 乘客等級(1/2/3等艙位)
· Name => 乘客姓名
· Sex => 性別
· Age => 年齡
· SibSp => 堂兄弟/妹個數(shù)
· Parch => 父母與小孩個數(shù)
· Ticket => 船票信息
· Fare => 票價
· Cabin => 客艙
· Embarked => 登船港口

逐條往下看,要看完這么多條,眼睛都有一種要瞎的趕腳。好吧,我們讓dataframe自己告訴我們一些信息,如下所示:

data_train.info()

看到了如下的信息: 


上面的數(shù)據(jù)說啥了?它告訴我們,訓(xùn)練數(shù)據(jù)中總共有891名乘客,但是很不幸,我們有些屬性的數(shù)據(jù)不全,比如說:

· Age(年齡)屬性只有714名乘客有記錄
· Cabin(客艙)更是只有204名乘客是已知的
似乎信息略少啊,想再瞄一眼具體數(shù)據(jù)數(shù)值情況呢?恩,我們用下列的方法,得到數(shù)值型數(shù)據(jù)的一些分布(因為有些屬性,比如姓名,是文本型;而另外一些屬性,比如登船港口,是類目型。這些我們用下面的函數(shù)是看不到的):


我們從上面看到更進一步的什么信息呢? 

mean字段告訴我們,大概0.383838的人最后獲救了,2/3等艙的人數(shù)比1等艙要多,平均乘客年齡大概是29.7歲(計算這個時候會略掉無記錄的)等等…

04 數(shù)據(jù)初步分析

每個乘客都這么多屬性,那我們咋知道哪些屬性更有用,而又應(yīng)該怎么用它們???僅僅最上面的對數(shù)據(jù)了解,依舊無法給我們提供想法和思路。我們再深入一點來看看我們的數(shù)據(jù),看看每個/多個 屬性和最后的Survived之間有著什么樣的關(guān)系呢。

4.1 乘客各屬性分布

腦容量太有限了…數(shù)值看花眼了。我們還是統(tǒng)計統(tǒng)計,畫些圖來看看屬性和結(jié)果之間的關(guān)系好了,代碼如下:

import matplotlib.pyplot as plt
fig = plt.figure()
fig.set(alpha=0.2)  # 設(shè)定圖表顏色alpha參數(shù)plt.subplot2grid((2,3),(0,0))             # 在一張大圖里分列幾個小圖data_train.Survived.value_counts().plot(kind='bar')# 柱狀圖 plt.title(u"獲救情況 (1為獲救)") # 標(biāo)題plt.ylabel(u"人數(shù)")  

plt.subplot2grid((2,3),(0,1))
data_train.Pclass.value_counts().plot(kind="bar")
plt.ylabel(u"人數(shù)")
plt.title(u"乘客等級分布")

plt.subplot2grid((2,3),(0,2))
plt.scatter(data_train.Survived, data_train.Age)
plt.ylabel(u"年齡")                         # 設(shè)定縱坐標(biāo)名稱plt.grid(b=True, which='major', axis='y') 
plt.title(u"按年齡看獲救分布 (1為獲救)")


plt.subplot2grid((2,3),(1,0), colspan=2)
data_train.Age[data_train.Pclass == 1].plot(kind='kde')   
data_train.Age[data_train.Pclass == 2].plot(kind='kde')
data_train.Age[data_train.Pclass == 3].plot(kind='kde')
plt.xlabel(u"年齡")# plots an axis lableplt.ylabel(u"密度") 
plt.title(u"各等級的乘客年齡分布")
plt.legend((u'頭等艙', u'2等艙',u'3等艙'),loc='best') # sets our legend for our graph.plt.subplot2grid((2,3),(1,2))
data_train.Embarked.value_counts().plot(kind='bar')
plt.title(u"各登船口岸上船人數(shù)")
plt.ylabel(u"人數(shù)")  
plt.show()



bingo,圖還是比數(shù)字好看多了。所以我們在圖上可以看出來,被救的人300多點,不到半數(shù);3等艙乘客灰常多;遇難和獲救的人年齡似乎跨度都很廣;3個不同的艙年齡總體趨勢似乎也一致,2/3等艙乘客20歲多點的人最多,1等艙40歲左右的最多(→_→似乎符合財富和年齡的分配哈,咳咳,別理我,我瞎扯的);登船港口人數(shù)按照S、C、Q遞減,而且S遠多于另外倆港口。

這個時候我們可能會有一些想法了:

· 不同艙位/乘客等級可能和財富/地位有關(guān)系,最后獲救概率可能會不一樣

· 年齡對獲救概率也一定是有影響的,畢竟前面說了,副船長還說『小孩和女士先走』呢

· 和登船港口是不是有關(guān)系呢?也許登船港口不同,人的出身地位不同?


口說無憑,空想無益。老老實實再來統(tǒng)計統(tǒng)計,看看這些屬性值的統(tǒng)計分布吧。

4.2 屬性與獲救結(jié)果的關(guān)聯(lián)統(tǒng)計

#看看各乘客等級的獲救情況fig = plt.figure()
fig.set(alpha=0.2)  # 設(shè)定圖表顏色alpha參數(shù)Survived_0 = data_train.Pclass[data_train.Survived == 0].value_counts()
Survived_1 = data_train.Pclass[data_train.Survived == 1].value_counts()
df=pd.DataFrame({u'獲救':Survived_1, u'未獲救':Survived_0})
df.plot(kind='bar', stacked=True)
plt.title(u"各乘客等級的獲救情況")
plt.xlabel(u"乘客等級") 
plt.ylabel(u"人數(shù)") 
plt.show()



嘖嘖,果然,錢和地位對艙位有影響,進而對獲救的可能性也有影響啊←_← 

咳咳,跑題了,我想說的是,明顯等級為1的乘客,獲救的概率高很多。恩,這個一定是影響最后獲救結(jié)果的一個特征。

#看看各性別的獲救情況fig = plt.figure()
fig.set(alpha=0.2)  # 設(shè)定圖表顏色alpha參數(shù)Survived_m = data_train.Survived[data_train.Sex == 'male'].value_counts()
Survived_f = data_train.Survived[data_train.Sex == 'female'].value_counts()
df=pd.DataFrame({u'男性':Survived_m, u'女性':Survived_f})
df.plot(kind='bar', stacked=True)
plt.title(u"按性別看獲救情況")
plt.xlabel(u"性別") 
plt.ylabel(u"人數(shù)")
plt.show()


歪果盆友果然很尊重lady,lady first踐行得不錯。性別無疑也要作為重要特征加入最后的模型之中。


恩,堅定了之前的判斷。

我們看看各登船港口的獲救情況。


下面我們來看看 堂兄弟/妹,孩子/父母有幾人,對是否獲救的影響。


好吧,沒看出特別特別明顯的規(guī)律(為自己的智商感到捉急…),先作為備選特征,放一放。
部分結(jié)果如下: 

這三三兩兩的…如此不集中…我們猜一下,也許,前面的ABCDE是指的甲板位置、然后編號是房間號?…好吧,我瞎說的,別當(dāng)真…

關(guān)鍵是Cabin這鬼屬性,應(yīng)該算作類目型的,本來缺失值就多,還如此不集中,注定是個棘手貨…第一感覺,這玩意兒如果直接按照類目特征處理的話,太散了,估計每個因子化后的特征都拿不到什么權(quán)重。加上有那么多缺失值,要不我們先把Cabin缺失與否作為條件(雖然這部分信息缺失可能并非未登記,maybe只是丟失了而已,所以這樣做未必妥當(dāng)),先在有無Cabin信息這個粗粒度上看看Survived的情況好了。


咳咳,有Cabin記錄的似乎獲救概率稍高一些,先這么著放一放吧。

05 簡單數(shù)據(jù)預(yù)處理

大體數(shù)據(jù)的情況看了一遍,對感興趣的屬性也有個大概的了解了。 

下一步干啥?咱們該處理處理這些數(shù)據(jù),為機器學(xué)習(xí)建模做點準(zhǔn)備了。

對了,我這里說的數(shù)據(jù)預(yù)處理,其實就包括了很多Kaggler津津樂道的feature engineering過程,灰?;页S斜匾?!

先從最突出的數(shù)據(jù)屬性開始吧,對,Cabin和Age,有丟失數(shù)據(jù)實在是對下一步工作影響太大。

先說Cabin,暫時我們就按照剛才說的,按Cabin有無數(shù)據(jù),將這個屬性處理成Yes和No兩種類型吧。

再說Age:

通常遇到缺值的情況,我們會有幾種常見的處理方式

· 如果缺值的樣本占總數(shù)比例極高,我們可能就直接舍棄了,作為特征加入的話,可能反倒帶入noise,影響最后的結(jié)果了
· 如果缺值的樣本適中,而該屬性非連續(xù)值特征屬性(比如說類目屬性),那就把NaN作為一個新類別,加到類別特征
· 如果缺值的樣本適中,而該屬性為連續(xù)值特征屬性,有時候我們會考慮給定一個step(比如這里的age,我們可以考慮每隔2/3歲為一個步長),然后把它離散化,之后把NaN作為一個type加到屬性類目中。
· 有些情況下,缺失的值個數(shù)并不是特別多,那我們也可以試著根據(jù)已有的值,擬合一下數(shù)據(jù),補充上。

本例中,后兩種處理方式應(yīng)該都是可行的,我們先試試擬合補全吧(雖然說沒有特別多的背景可供我們擬合,這不一定是一個多么好的選擇)

我們這里用scikit-learn中的RandomForest來擬合一下缺失的年齡數(shù)據(jù)(注:RandomForest是一個用在原始數(shù)據(jù)中做不同采樣,建立多顆DecisionTree,再進行average等等來降低過擬合現(xiàn)象,提高結(jié)果的機器學(xué)習(xí)算法,我們之后會介紹到)


恩。目的達到,OK了。

因為邏輯回歸建模時,需要輸入的特征都是數(shù)值型特征,我們通常會先對類目型的特征因子化。 

什么叫做因子化呢?舉個例子:

以Cabin為例,原本一個屬性維度,因為其取值可以是[‘yes’,’no’],而將其平展開為’Cabin_yes’,’Cabin_no’兩個屬性

原本Cabin取值為yes的,在此處的”Cabin_yes”下取值為1,在”Cabin_no”下取值為0
原本Cabin取值為no的,在此處的”Cabin_yes”下取值為0,在”Cabin_no”下取值為1
我們使用pandas的”get_dummies”來完成這個工作,并拼接在原來的”data_train”之上,如下所示。



bingo,我們很成功地把這些類目屬性全都轉(zhuǎn)成0,1的數(shù)值屬性了。

這樣,看起來,是不是我們需要的屬性值都有了,且它們都是數(shù)值型屬性呢。

有一種臨近結(jié)果的寵寵欲動感吧,莫急莫急,我們還得做一些處理,仔細看看Age和Fare兩個屬性,乘客的數(shù)值幅度變化,也忒大了吧!!如果大家了解邏輯回歸與梯度下降的話,會知道,各屬性值之間scale差距太大,將對收斂速度造成幾萬點傷害值!甚至不收斂! (╬▔皿▔)…所以我們先用scikit-learn里面的preprocessing模塊對這倆貨做一個scaling,所謂scaling,其實就是將一些變化幅度較大的特征化到[-1,1]之內(nèi)。


恩,好看多了,萬事俱備,只欠建模。馬上就要看到成效了,哈哈。我們把需要的屬性值抽出來,轉(zhuǎn)成scikit-learn里面LogisticRegression可以處理的格式。

06 邏輯回歸建模

我們把需要的feature字段取出來,轉(zhuǎn)成numpy格式,使用scikit-learn中的LogisticRegression建模。

good,很順利,我們得到了一個model,如下: 


先淡定!淡定!你以為把test.csv直接丟進model里就能拿到結(jié)果啊…騷年,圖樣圖森破??!我們的”test_data”也要做和”train_data”一樣的預(yù)處理啊??!


不錯不錯,數(shù)據(jù)很OK,差最后一步了。 

下面就做預(yù)測取結(jié)果吧??!


嘖嘖,挺好,格式正確,去make a submission啦啦啦!

在Kaggle的Make a submission頁面,提交上結(jié)果。如下: 



0.76555,恩,結(jié)果還不錯。畢竟,這只是我們簡單分析處理過后出的一個baseline模型嘛。

07 邏輯回歸系統(tǒng)優(yōu)化

7.1 模型系數(shù)關(guān)聯(lián)分析

親,你以為結(jié)果提交上了,就完事了? 

我不會告訴你,這只是萬里長征第一步啊(淚牛滿面)?。?!這才剛擼完baseline model啊?。?!還得優(yōu)化?。。?!

看過Andrew Ng老師的machine Learning課程的同學(xué)們,知道,我們應(yīng)該分析分析模型現(xiàn)在的狀態(tài)了,是過/欠擬合?,以確定我們需要更多的特征還是更多數(shù)據(jù),或者其他操作。我們有一條很著名的learning curves對吧。

不過在現(xiàn)在的場景下,先不著急做這個事情,我們這個baseline系統(tǒng)還有些粗糙,先再挖掘挖掘。

首先,Name和Ticket兩個屬性被我們完整舍棄了(好吧,其實是因為這倆屬性,幾乎每一條記錄都是一個完全不同的值,我們并沒有找到很直接的處理方式)。

然后,我們想想,年齡的擬合本身也未必是一件非常靠譜的事情,我們依據(jù)其余屬性,其實并不能很好地擬合預(yù)測出未知的年齡。再一個,以我們的日常經(jīng)驗,小盆友和老人可能得到的照顧會多一些,這樣看的話,年齡作為一個連續(xù)值,給一個固定的系數(shù),應(yīng)該和年齡是一個正相關(guān)或者負(fù)相關(guān),似乎體現(xiàn)不出兩頭受照顧的實際情況,所以,說不定我們把年齡離散化,按區(qū)段分作類別屬性會更合適一些。

上面只是我瞎想的,who knows是不是這么回事呢,老老實實先把得到的model系數(shù)和feature關(guān)聯(lián)起來看看。

pd.DataFrame({"columns":list(train_df.columns)[1:], "coef":list(clf.coef_.T)})
1

首先,大家回去前兩篇文章里瞄一眼公式就知道,這些系數(shù)為正的特征,和最后結(jié)果是一個正相關(guān),反之為負(fù)相關(guān)。

我們先看看那些權(quán)重絕對值非常大的feature,在我們的模型上:

· Sex屬性,如果是female會極大提高最后獲救的概率,而male會很大程度拉低這個概率。
· Pclass屬性,1等艙乘客最后獲救的概率會上升,而乘客等級為3會極大地拉低這個概率。
· 有Cabin值會很大程度拉升最后獲救概率(這里似乎能看到了一點端倪,事實上從最上面的有無Cabin記錄的Survived分布圖上看出,即使有Cabin記錄的乘客也有一部分遇難了,估計這個屬性上我們挖掘還不夠)
· Age是一個負(fù)相關(guān),意味著在我們的模型里,年齡越小,越有獲救的優(yōu)先權(quán)(還得回原數(shù)據(jù)看看這個是否合理)
· 有一個登船港口S會很大程度拉低獲救的概率,另外倆港口壓根就沒啥作用(這個實際上非常奇怪,因為我們從之前的統(tǒng)計圖上并沒有看到S港口的獲救率非常低,所以也許可以考慮把登船港口這個feature去掉試試)。
· 船票Fare有小幅度的正相關(guān)(并不意味著這個feature作用不大,有可能是我們細化的程度還不夠,舉個例子,說不定我們得對它離散化,再分至各個乘客等級上?)

噢啦,觀察完了,我們現(xiàn)在有一些想法了,但是怎么樣才知道,哪些優(yōu)化的方法是promising的呢?

因為test.csv里面并沒有Survived這個字段(好吧,這是廢話,這明明就是我們要預(yù)測的結(jié)果),我們無法在這份數(shù)據(jù)上評定我們算法在該場景下的效果…

而『每做一次調(diào)整就make a submission,然后根據(jù)結(jié)果來判定這次調(diào)整的好壞』其實是行不通的…

7.2 交叉驗證

我們通常情況下,這么做cross validation:把train.csv分成兩部分,一部分用于訓(xùn)練我們需要的模型,另外一部分?jǐn)?shù)據(jù)上看我們預(yù)測算法的效果。

我們用scikit-learn的cross_validation來幫我們完成小數(shù)據(jù)集上的這個工作。

先簡單看看cross validation情況下的打分

結(jié)果是下面醬紫的: 

[0.81564246 0.81005587 0.78651685 0.78651685 0.81355932]

似乎比Kaggle上的結(jié)果略高哈,畢竟用的是不是同一份數(shù)據(jù)集評估的。

等等,既然我們要做交叉驗證,那我們干脆先把交叉驗證里面的bad case拿出來看看,看看人眼審核,是否能發(fā)現(xiàn)什么蛛絲馬跡,是我們忽略了哪些信息,使得這些乘客被判定錯了。再把bad case上得到的想法和前頭系數(shù)分析的合在一起,然后逐個試試。

下面我們做數(shù)據(jù)分割,并且在原始數(shù)據(jù)集上瞄一眼bad case:

我們判定錯誤的 bad case 中部分?jǐn)?shù)據(jù)如下: 


大家可以自己跑一遍試試,拿到bad cases之后,仔細看看。也會有一些猜測和想法。其中會有一部分可能會印證在系數(shù)分析部分的猜測,那這些優(yōu)化的想法優(yōu)先級可以放高一些。
現(xiàn)在有了”train_df” 和 “vc_df” 兩個數(shù)據(jù)部分,前者用于訓(xùn)練model,后者用于評定和選擇模型??梢蚤_始可勁折騰了。

我們隨便列一些可能可以做的優(yōu)化操作:

· Age屬性不使用現(xiàn)在的擬合方式,而是根據(jù)名稱中的『Mr』『Mrs』『Miss』等的平均值進行填充。
· Age不做成一個連續(xù)值屬性,而是使用一個步長進行離散化,變成離散的類目feature。
· Cabin再細化一些,對于有記錄的Cabin屬性,我們將其分為前面的字母部分(我猜是位置和船層之類的信息) 和 后面的數(shù)字部分(應(yīng)該是房間號,有意思的事情是,如果你仔細看看原始數(shù)據(jù),你會發(fā)現(xiàn),這個值大的情況下,似乎獲救的可能性高一些)。
· Pclass和Sex倆太重要了,我們試著用它們?nèi)ソM出一個組合屬性來試試,這也是另外一種程度的細化。
· 單加一個Child字段,Age<=12的,設(shè)為1,其余為0(你去看看數(shù)據(jù),確實小盆友優(yōu)先程度很高啊)
· 如果名字里面有『Mrs』,而Parch>1的,我們猜測她可能是一個母親,應(yīng)該獲救的概率也會提高,因此可以多加一個Mother字段,此種情況下設(shè)為1,其余情況下設(shè)為0
· 登船港口可以考慮先去掉試試(Q和C本來就沒權(quán)重,S有點詭異)
· 把堂兄弟/兄妹 和 Parch 還有自己 個數(shù)加在一起組一個Family_size字段(考慮到大家族可能對最后的結(jié)果有影響)
· Name是一個我們一直沒有觸碰的屬性,我們可以做一些簡單的處理,比如說男性中帶某些字眼的(‘Capt’, ‘Don’, ‘Major’, ‘Sir’)可以統(tǒng)一到一個Title,女性也一樣。

大家接著往下挖掘,可能還可以想到更多可以細挖的部分。我這里先列這些了,然后我們可以使用手頭上的”train_df”和”cv_df”開始試驗這些feature engineering的tricks是否有效了。

試驗的過程比較漫長,也需要有耐心,而且我們經(jīng)常會面臨很尷尬的狀況,就是我們靈光一閃,想到一個feature,然后堅信它一定有效,結(jié)果試驗下來,效果還不如試驗之前的結(jié)果。恩,需要堅持和耐心,以及不斷的挖掘。

我最好的結(jié)果是在

『Survived~C(Pclass)+C(Title)+C(Sex)+C(Age_bucket)+C(Cabin_num_bucket)Mother+Fare+Family_Size』下取得的,結(jié)果如下(抱歉,之前commit的時候沒有截圖,于是重新make commission了,截了個圖,不是目前我的最高分哈):



7.3 learning curves

有一個很可能發(fā)生的問題是,我們不斷地做feature engineering,產(chǎn)生的特征越來越多,用這些特征去訓(xùn)練模型,會對我們的訓(xùn)練集擬合得越來越好,同時也可能在逐步喪失泛化能力,從而在待預(yù)測的數(shù)據(jù)上,表現(xiàn)不佳,也就是發(fā)生過擬合問題。

從另一個角度上說,如果模型在待預(yù)測的數(shù)據(jù)上表現(xiàn)不佳,除掉上面說的過擬合問題,也有可能是欠擬合問題,也就是說在訓(xùn)練集上,其實擬合的也不是那么好。

額,這個欠擬合過擬合怎么解釋呢。這么說吧:

· 過擬合就像是你班那個學(xué)數(shù)學(xué)比較刻板的同學(xué),老師講過的題目,一字不漏全記下來了,于是老師再出一樣的題目,分分鐘精確出結(jié)果。but數(shù)學(xué)考試,因為總是碰到新題目,所以成績不咋地。
· 欠擬合就像是,咳咳,和博主level差不多的差生。連老師講的練習(xí)題也記不住,于是連老師出一樣題目復(fù)習(xí)的周測都做不好,考試更是可想而知了。
而在機器學(xué)習(xí)的問題上,對于過擬合欠擬合兩種情形。我們優(yōu)化的方式是不同的。
過擬合而言,通常以下策略對結(jié)果優(yōu)化是有用的:
· 做一下feature selection,挑出較好的feature的subset來做training
· 提供更多的數(shù)據(jù),從而彌補原始數(shù)據(jù)的bias問題,學(xué)習(xí)到的model也會更準(zhǔn)確
而對于欠擬合而言,我們通常需要更多的feature,更復(fù)雜的模型來提高準(zhǔn)確度。

著名的learning curve可以幫我們判定我們的模型現(xiàn)在所處的狀態(tài)。我們以樣本數(shù)為橫坐標(biāo),訓(xùn)練和交叉驗證集上的錯誤率作為縱坐標(biāo),兩種狀態(tài)分別如下兩張圖所示:過擬合(overfitting/high variace),欠擬合(underfitting/high bias)



我們也可以把錯誤率替換成準(zhǔn)確率(得分),得到另一種形式的learning curve(sklearn 里面是這么做的)。

回到我們的問題,我們用scikit-learn里面的learning_curve來幫我們分辨我們模型的狀態(tài)。舉個例子,這里我們一起畫一下我們最先得到的baseline model的learning curve。


在實際數(shù)據(jù)上看,我們得到的learning curve沒有理論推導(dǎo)的那么光滑哈,但是可以大致看出來,訓(xùn)練集和交叉驗證集上的得分曲線走勢還是符合預(yù)期的。

目前的曲線看來,我們的model并不處于overfitting的狀態(tài)(overfitting的表現(xiàn)一般是訓(xùn)練集上得分高,而交叉驗證集上要低很多,中間的gap比較大)。因此我們可以再做些feature engineering的工作,添加一些新產(chǎn)出的特征或者組合特征到模型中。


08 模型融合(model ensemble)

啥叫模型融合呢,我們還是舉幾個例子直觀理解一下好了。

大家都看過知識問答的綜藝節(jié)目中,求助現(xiàn)場觀眾時候,讓觀眾投票,最高的答案作為自己的答案的形式吧,每個人都有一個判定結(jié)果,最后我們相信答案在大多數(shù)人手里。

再通俗一點舉個例子。你和你班某數(shù)學(xué)大神關(guān)系好,每次作業(yè)都『模仿』他的,于是絕大多數(shù)情況下,他做對了,你也對了。突然某一天大神腦子犯糊涂,手一抖,寫錯了一個數(shù),于是…恩,你也只能跟著錯了。 

我們再來看看另外一個場景,你和你班5個數(shù)學(xué)大神關(guān)系都很好,每次都把他們作業(yè)拿過來,對比一下,再『自己做』,那你想想,如果哪天某大神犯糊涂了,寫錯了,but另外四個寫對了啊,那你肯定相信另外4人的是正確答案吧?

最簡單的模型融合大概就是這么個意思,比如分類問題,當(dāng)我們手頭上有一堆在同一份數(shù)據(jù)集上訓(xùn)練得到的分類器(比如logistic regression,SVMKNN,random forest,神經(jīng)網(wǎng)絡(luò)),那我們讓他們都分別去做判定,然后對結(jié)果做投票統(tǒng)計,取票數(shù)最多的結(jié)果為最后結(jié)果。

bingo,問題就這么完美的解決了。

模型融合可以比較好地緩解,訓(xùn)練過程中產(chǎn)生的過擬合問題,從而對于結(jié)果的準(zhǔn)確度提升有一定的幫助。

話說回來,回到我們現(xiàn)在的問題。你看,我們現(xiàn)在只講了logistic regression,如果我們還想用這個融合思想去提高我們的結(jié)果,我們該怎么做呢?

既然這個時候模型沒得選,那咱們就在數(shù)據(jù)上動動手腳咯。大家想想,如果模型出現(xiàn)過擬合現(xiàn)在,一定是在我們的訓(xùn)練上出現(xiàn)擬合過度造成的對吧。

那我們干脆就不要用全部的訓(xùn)練集,每次取訓(xùn)練集的一個subset,做訓(xùn)練,這樣,我們雖然用的是同一個機器學(xué)習(xí)算法,但是得到的模型卻是不一樣的;同時,因為我們沒有任何一份子數(shù)據(jù)集是全的,因此即使出現(xiàn)過擬合,也是在子訓(xùn)練集上出現(xiàn)過擬合,而不是全體數(shù)據(jù)上,這樣做一個融合,可能對最后的結(jié)果有一定的幫助。對,這就是常用的Bagging。
我們用scikit-learn里面的Bagging來完成上面的思路,過程非常簡單。代碼如下:

然后你再Make a submission,恩,發(fā)現(xiàn)對結(jié)果還是有幫助的。



09 總結(jié)
文章稍微有點長,非常感謝各位耐心看到這里。 

總結(jié)的部分,我就簡短寫幾段,出現(xiàn)的話,很多在文中有對應(yīng)的場景,大家有興趣再回頭看看。

對于任何的機器學(xué)習(xí)問題,不要一上來就追求盡善盡美,先用自己會的算法擼一個baseline的model出來,再進行后續(xù)的分析步驟,一步步提高。

在問題的結(jié)果過程中: 

* 『對數(shù)據(jù)的認(rèn)識太重要了!』 
* 『數(shù)據(jù)中的特殊點/離群點的分析和處理太重要了!』 
* 『特征工程(feature engineering)太重要了!』 
* 『模型融合(model ensemble)太重要了!』

本文中用機器學(xué)習(xí)解決問題的過程大概如下圖所示: 


順便說一句,CDA數(shù)據(jù)分析競賽正在籌備中,想要參加比賽或者和我們合作的可以后臺回復(fù)“CDA數(shù)據(jù)分析競賽”加入我們。

數(shù)據(jù)分析咨詢請掃描二維碼

若不方便掃碼,搜微信號:CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個參數(shù)驗證碼對象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺檢測極驗服務(wù)器是否宕機 new_captcha: data.new_captcha, // 用于宕機時表示是新驗證碼的宕機 product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說明請參見:http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計時完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }