一個實例告訴你:Kaggle 數據競賽都有哪些套路
前面寫了很多篇理論,大家願意一篇一篇堅持看下來其實挺不容易的,雖然理論很重要,但脫離了實踐還是空中樓閣啊,演算法科學家也不可能不代碼啊,所以呀,今天我們就插播一期實踐,和大家聊一聊實際過程當中機器學習演算法的應用。
對於我們這些初學者或者說外行來說,因為我們沒機會接觸到機器學習真正的應用項目,所以一些比賽平台往往是我們不錯的選擇,比如說這個Kaggle啊,前一段時間被Google收購還挺火的,還有國內的天池啊,DataFountain啊,上面都有不少比賽可以選擇,但是入門嘛,我們就從最簡單的開始,就是那個被無數文章博客提到過的泰坦尼克倖存者估計,我自己也看過一些,但是覺得很多文章把一開始數據探索部分寫得太重了,反而後面特徵選擇和模型調參講的很少,我感覺這樣有些本末倒置的感覺,數據和特徵決定了我們的上限。這裡呢,我主要想講的就是完成一個數據競賽的整個流程以及其中最常見的一些套路,希望可以幫助大家可以快速入門競賽,以期取得好成績或者給自己求職增添砝碼。
下面進入正題:
首先我們先觀察一下我們的數據,看看哪些可以構建為我們的特徵
import pandas as pd
data=pd.read_csv( E:BlogTitanicTrain.csv )
data.info()
data.describe()
所有的數據中一共包括12個變數,其中7個是數值變數,5個是屬性變數,接下來我們具體來看一看。
PassengerId:這是乘客的編號,顯然對乘客是否倖存完全沒有任何作用,僅做區分作用,所以我們就不考慮它了。
Survived:乘客最後的生存情況,這個是我們預測的目標變數。不過從平均數可以看出,最後存活的概率大概是38%。
Pclass:社會經濟地位,這個很明顯和生存結果相關啊,有錢人住著更加高級船艙可能會享受著更加高級的服務,因此遇險時往往會受到優待。所以這顯然是我們要考慮的一個變數。
Name:這個變數看起來好像是沒什麼用啊,因為畢竟從名字你也不能看出能不能獲救,但是仔細觀察數據我們可以看到,所有人的名字里都包括了Mr,Mrs和Miss,從中是不是隱約可以看出來一些性別和年齡的信息呢,所以乾脆把名字這個變數變成一個狀態變數,包含Mr,Mrs和Miss這三種狀態,但是放到機器學習裡面我們得給它一個編碼啊,最直接的想法就是0,1,2,但是這樣真的合理嗎?因為從距離的角度來說,這樣Mr和Mrs的距離要小於Mr和Miss的距離,顯然不合適,因為我們把它看成平權的三個狀態。
所以,敲黑板,知識點來了,對於這種狀態變數我們通常採取的措施是one-hot編碼,什麼意思呢,有幾種狀態就用一個幾位的編碼來表示狀態,每種狀態對應一個一位是1其餘各位是0的編碼,這樣從向量的角度來講,就是n維空間的n個基準向量,它們相互明顯是平權的,此例中,我們分別用100,010,001來表示Mr,Mrs和Miss。
Sex:性別這個屬性肯定是很重要的,畢竟全人類都講究Lady First,所以遇到危險的時候,紳士們一定會先讓女士逃走,因此女性的生存幾率應該會大大提高。類似的,性別也是一個平權的狀態變數,所以到時候我們同樣採取one-hot編碼的方式進行處理。
Age:這個變數和性別類似,都是明顯會發揮重要作用的,因為無論何時,尊老愛幼總是為人們所推崇,但年齡對是否會獲救的影響主要體現在那個人處在哪個年齡段,因此我們選擇將它劃分成一個狀態變數,比如18以下叫child,18以上50以下叫adult,50以上叫elder,然後利用one-hot編碼進行處理。不過這裡還有一個問題就是年齡的值只有714個,它不全!這麼重要的東西怎麼能不全呢,所以我們只能想辦法補全它。
又敲黑板,知識點又來了,缺失值我們怎麼處理呢?最簡單的方法,有缺失值的樣本我們就扔掉,這種做法比較適合在樣本數量很多,缺失值樣本捨棄也可以接受的情況下,這樣雖然信息用的不充分,但也不會引入額外的誤差。然後,假裝走心的方法就是用平均值或者中位數來填充缺失值,這通常是最簡便的做法,但通常會帶來不少的誤差。最後,比較負責任的方法就是利用其它的變數去估計缺失變數的值,這樣通常會更靠譜一點,當然也不能完全這樣說,畢竟只要是估計值就不可避免的帶來誤差,但心理上總會覺得這樣更好……
SibSp:船上兄弟姐妹或者配偶的數量。這個變數對最後的結果到底有什麼影響我還真的說不準,但是預測年紀的時候說不定有用。
Parch:船上父母或者孩子的數量。這個變數和上個變數類似,我確實沒有想到特別好的應用它的辦法,同樣的,預測年齡時這個應該挺靠譜的。
Ticket:船票的號碼。恕我直言,這個謎一樣的數字真的是不知道有什麼鬼用,果斷放棄了。
Fare:船票價格,這個變數的作用其實類似於社會地位,船票價格越高,享受的服務越高檔,所以遇難獲救的概率肯定相對較高,所以這是一個必須要考慮進去的變數。
Cabin:船艙號,這個變數或許透露出了一點船艙等級的信息,但是說實話,你的缺失值實在是太多了,我要是把它補全引入的誤差感覺比它提供的信息還多,所以忍痛割愛,和你say goodbye!
Embarked:登船地點,按道理來說,這個變數應該是沒什麼卵用的,但介於它是一個只有三個狀態的狀態變數,那我們就把它處理一下放進模型,萬一有用呢對吧。另外,它有兩個缺失值,這裡我們就不大動干戈的去預測了,就直接把它定為登船人數最多的S吧。
好的,到這裡我們對所有變數應該如何處理大致有譜了,狀態變數進行one-hot編碼,那數值變數呢,直接用嗎?
知識點!對於數值變數,我們通常會先進行歸一化處理,這樣有利於我們加快收斂速度,將各個維度限制在差不多的區間內,對一些基於距離的分類器有著非常大的好處,但是對於決策樹一類的演算法其實就沒有意義了,不過這邊我們就對所有的數值變數都做一個歸一化處理吧。
到了這裡,想必思路已經很清晰了,下面我們再梳理一下過程:
1 剔除PassengerId,Ticket這兩個個變數,我們不用。
2 將Embarked變數補全,然後對Survived,Name,Sex, Embarked進行one-hot編碼。
3對Pclass,Fare,Sibsp和Parch進行歸一化處理。
3 根據Name,Sex,SibSp,Parch預測age將其補全。
4 對age進行歸一化處理。
5 將未編碼的Survived提出當做目標變數。
具體的代碼實現如下:
import pandas as pd
data=pd.read_csv( E:BlogTitanicTrain.csv )
#剔除變數
data.drop([ PassengerId , Ticket ],axis=1,inplace=True)
#補全Embarked變數
data.loc[data.Embarked.isnull(), Embarked ]= S
#one-hot編碼
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
#ohe_pclass=OneHotEncoder(sparse=False).fit(data[[ Pclass ]])
#Pclass_ohe=ohe_pclass.transform(data[[ Pclass ]])
le_sex=LabelEncoder().fit(data[ Sex ])
Sex_label=le_sex.transform(data[ Sex ])
ohe_sex=OneHotEncoder(sparse=False).fit(Sex_label.reshape(-1,1))
Sex_ohe=ohe_sex.transform(Sex_label.reshape(-1,1))
le_embarked=LabelEncoder().fit(data[ Embarked ])
Embarked_label=le_embarked.transform(data[ Embarked ])
ohe_embarked=OneHotEncoder(sparse=False).fit(Embarked_label.reshape(-1,1))
Embarked_ohe=ohe_embarked.transform(Embarked_label.reshape(-1,1))
def replace_name(x):
if Mrs in x:
return Mrs
elif Mr in x:
return Mr
else:
return Miss
data[ Name ]=data[ Name ].map(lambda x:replace_name(x))
le_name=LabelEncoder().fit(data[ Name ])
Name_label=le_name.transform(data[ Name ])
ohe_name=OneHotEncoder(sparse=False).fit(Name_label.reshape(-1,1))
Name_ohe=ohe_name.transform(Name_label.reshape(-1,1))
data[ Sex_0 ]=Sex_ohe[:,0]
data[ Sex_1 ]=Sex_ohe[:,1]
data[ Embarked_0 ]=Embarked_ohe[:,0]
data[ Embarked_1 ]=Embarked_ohe[:,1]
data[ Embarked_2 ]=Embarked_ohe[:,2]
data[ Name_0 ]=Name_ohe[:,0]
data[ Name_1 ]=Name_ohe[:,1]
data[ Name_2 ]=Name_ohe[:,2]
#歸一化處理
from sklearn.preprocessing import StandardScaler
Pclass_scale=StandardScaler().fit(data[ Pclass ])
data[ Pclass_scaled ]=StandardScaler().fit_transform(data[ Pclass ].reshape(-1,1),Pclass_scale)
Fare_scale=StandardScaler().fit(data[ Fare ])
data[ Fare_scaled ]=StandardScaler().fit_transform(data[ Fare ].reshape(-1,1),Fare_scale)
SibSp_scale=StandardScaler().fit(data[ SibSp ])
data[ SibSp_scaled ]=StandardScaler().fit_transform(data[ SibSp ].reshape(-1,1),SibSp_scale)
Parch_scale=StandardScaler().fit(data[ Parch ])
data[ Parch_scaled ]=StandardScaler().fit_transform(data[ Parch ].reshape(-1,1),Parch_scale)
#預測年紀並補全
from sklearn.ensemble import RandomForestRegressor
def set_missing_age(data):
train=data[[ Age , SibSp_scaled , Parch_scaled , Name_0 , Name_1 , Name_2 , Sex_0 , Sex_1 ]]
known_age=train[train.Age.notnull()].as_matrix()
unknown_age=train[train.Age.isnull()].as_matrix()
y=known_age[:,0]
x=known_age[:,1:]
rf=RandomForestRegressor(random_state=0,n_estimators=200,n_jobs=-1)
rf.fit(x,y)
print rf.score(x,y)
predictage=rf.predict(unknown_age[:,1:])
data.loc[data.Age.isnull(), Age ]=predictage
return data,rf
data,rf=set_missing_age(data)
Age_scale=StandardScaler().fit(data[ Age ])
data[ Age_scaled ]=StandardScaler().fit_transform(data[ Age ].reshape(-1,1),Age_scale)
train_x=data[[ Sex_0 , Sex_1 , Embarked_0 , Embarked_1 , Embarked_2 , Name_0 , Name_1 , Name_2 , Pclass_scaled , Age_scaled , Fare_scaled ]].as_matrix()
train_y=data[ Survived ].as_matrix()
完成了我們的數據預處理和特徵工程之後,就開始選擇合適的機器學習模型來進行學習就ok了。
這很顯然是個分類問題,那麼我們現在可以的選擇有邏輯回歸(一個名字叫回歸卻干著分類器的活的傢伙),決策樹以及決策樹提升的一些演算法(包括什麼GDBT,AdaBoost,RandomForest等等),還有SVC,甚至聚類演算法我們都可以試試……不過呢,花板子我們就不玩了,這裡我們就選擇邏輯回歸,支持向量分類器,隨機森林分類器和梯度提升分類器來做一下,看看它們在訓練集上的表現如何:
#模型構造
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
x_tr,x_te,y_tr,y_te=train_test_split(train_x,train_y,test_size=0.3,random_state=0)
lr=LogisticRegression(C=1.0,tol=1e-6)
lr.fit(x_tr,y_tr)
print lr.score(x_te,y_te)
from sklearn.svm import SVC
svc=SVC(C=2, kernel= rbf , decision_function_shape= ovo )
svc.fit(x_tr,y_tr)
print svc.score(x_te,y_te)
from sklearn.ensemble import RandomForestClassifier
randomf=RandomForestClassifier(n_estimators=500,max_depth=5,random_state=0)
randomf.fit(x_tr,y_tr)
print randomf.score(x_te,y_te)
from sklearn.ensemble import GradientBoostingClassifier
gdbt=GradientBoostingClassifier(n_estimators=600,max_depth=5,random_state=0)
gdbt.fit(x_tr,y_tr)
print gdbt.score(x_te,y_te)
輸出的結果為
我們可以看出SVC的效果最好,當然這有一定的隨機性在裡面,那我們就改變一下劃分訓練集和測試集的種子,看看結果是否會發生變化,將Random_state的值改為1,輸出為
整體的正確率都發生了下降,但SVC的效果依然是做好的,所以我們不妨用SVC做一個結果先提交了看看正確率如何。那要想用這個模型進行預測,那我們要對測試集的數據做和訓練集數據同樣的事兒,包括補全無效值,預測年齡,one-hot編碼以及歸一化等等,只有這樣我們的訓練模型才能最大限度的發揮它的作用。完成預測之後,我們要將對應的ID和預測結果寫入一個csv文件提交,實現的代碼如下:
#預測數據
data_test=pd.read_csv( test.csv )
data_test.drop([ Ticket ],axis=1,inplace=True)
data_test.loc[data_test.Embarked.isnull(), Embarked ]= S
Sex_label_test=le_sex.transform(data_test[ Sex ])
Sex_ohe_test=ohe_sex.transform(Sex_label_test.reshape(-1,1))
Embarked_label_test=le_embarked.transform(data_test[ Embarked ])
Embarked_ohe_test=ohe_embarked.transform(Embarked_label_test.reshape(-1,1))
data_test[ Name ]=data_test[ Name ].map(lambda x:replace_name(x))
Name_label_test=le_name.transform(data_test[ Name ])
Name_ohe_test=ohe_name.transform(Name_label_test.reshape(-1,1))
data_test[ Sex_0 ]=Sex_ohe_test[:,0]
data_test[ Sex_1 ]=Sex_ohe_test[:,1]
data_test[ Embarked_0 ]=Embarked_ohe_test[:,0]
data_test[ Embarked_1 ]=Embarked_ohe_test[:,1]
data_test[ Embarked_2 ]=Embarked_ohe_test[:,2]
data_test[ Name_0 ]=Name_ohe_test[:,0]
data_test[ Name_1 ]=Name_ohe_test[:,1]
data_test[ Name_2 ]=Name_ohe_test[:,2]
data_test[ Pclass_scaled ]=StandardScaler().fit_transform(data_test[ Pclass ].reshape(-1,1),Pclass_scale)
data_test.loc[data_test.Fare.isnull(), Fare ]=0
data_test[ Fare_scaled ]=StandardScaler().fit_transform(data_test[ Fare ].reshape(-1,1),Fare_scale)
data_test[ SibSp_scaled ]=StandardScaler().fit_transform(data_test[ SibSp ].reshape(-1,1),SibSp_scale)
data_test[ Parch_scaled ]=StandardScaler().fit_transform(data_test[ Parch ].reshape(-1,1),Parch_scale)
train_test=data_test[[ Age , SibSp_scaled , Parch_scaled , Name_0 , Name_1 , Name_2 , Sex_0 , Sex_1 ]]
unknown_age_test=train_test[train_test.Age.isnull()].as_matrix()
x_test=unknown_age_test[:,1:]
predictage=rf.predict(x_test)
data_test.loc[data_test.Age.isnull(), Age ]=predictage
data_test[ Age_scaled ]=StandardScaler().fit_transform(data_test[ Age ].reshape(-1,1),Age_scale)
test_x=data_test[[ Sex_0 , Sex_1 , Embarked_0 , Embarked_1 , Embarked_2 , Name_0 , Name_1 , Name_2 , Pclass_scaled , Age_scaled , Fare_scaled ]].as_matrix()
predictions=model.predict(test_x).astype(np.int32)
result=pd.DataFrame({ PassengerId :data_test[ PassengerId ].as_matrix(), Survived :predictions})
result.to_csv( svc.csv ,index=False)
將結果提交到Kaggle的網站之後,我們發現我們的準確率是79.904%,居然已經進了20%了,還是蠻順利的嘛,那麼如何繼續提升我們的成績呢?最有效的方法莫過於構建新的特徵,尋找更有效的特徵永遠是提升正確率的王道。當然了,也有一些簡單的辦法有可能能幫助我們提高成績,那就是三個臭皮匠頂個諸葛亮。我們選擇幾個相關性不是很大的分類器,用它們預測的結果進行投票,往往一定程度上也能提高我們的成績,比如下面這種做法:
from sklearn.ensemble import VotingClassifier
model.fit(x_tr,y_tr)
print model.score(x_te,y_te)
輸出為:
測試集上的表現可真棒啊!!!這一下很大的鼓舞了我的信心,所以趕緊用這個模型做個結果提交一下看看。
結果,正確率變成了78.649%,正確率下降了,整段垮掉!!!前面說的那麼有模有樣,結果被無情的現實狠甩一記耳光啊……
不過最重要的還是這個思路,比如你可以和你的小夥伴各做一個模型,你們構建模型的思路肯定不一樣啊,那麼模型的相關性比較低,這樣組合起來提升效果應該比較明顯,我就強行這樣圓一下吧。
其實我相信到這裡大家也看出來了,做的這個模型我們還是把絕大數的時間花在了模型的構造上了,真正模型訓練啥的並沒有佔據我們太多的時間。所以還是那句話,數據和特徵決定了機器學習的上限,而模型和方法只能是逼近這個上限,好好做特徵吧。
註:本文作者成達,原文載於作者個人博客,雷鋒網 AI 研習社已獲授權。


※開放Alexa語音控制技術 亞馬遜欲打造最有影響力的聊天機器人開發平台
※史上最簡潔易懂教程 用Excel理解梯度下降
※人臉檢測與識別的趨勢和分析
TAG:唯物 |
※除了Kaggle,數據科學競賽平台還有哪些選擇?
※我贏得 Kaggle 競賽的第五名,這些經驗分享給你
※除了Kaggle,這裡還有一些含金量高的數據科學競賽哦
※如何達到Kaggle競賽top 2%?這裡有一篇特徵探索經驗帖
※除了Kaggle,這裡還有一些高質量的數據科學競賽平台
※XPrize正在重啟登月競賽 但這次沒有了Google的幫助
※業界 | 如何達到Kaggle競賽top 2%?這裡有一篇特徵探索經驗帖
※Yoshua Bengio:我不想看到各國AI競賽,對當前AI思路感到擔憂
※識別座頭鯨,Kaggle競賽第一名解決方案解讀
※不寫一行代碼就能玩轉 Kaggle 競賽?
※22分鐘直衝Kaggle競賽第二名!一文教你做到
※誰是數據競賽王者?CatBoost vs.Light GBM vs.XGBoost
※在AI競賽中獨步領先,看Kayak如何做到這一點
※millionairemansion.co.uk舉辦首屆以豪宅為獎品的全球競賽,勝出者將獲得一座英國宅邸
※兄dei,Python數據競賽和5萬現金獎勵了解一下
※Google AI地標檢索識別競賽雙料獲勝方案 | 飛槳PaddlePaddle開源
※從零開始,教你征戰Kaggle競賽
※Quora Question Pairs 競賽冠軍經驗分享:採用 4 層堆疊,經典模型比較給力
※進入 kaggle 競賽前 2% 的秘訣
※球鞋科技競賽,總有一款你pick