Python機器學習小試...泰坦尼克號開啟的kaggle入門
學習了線性回歸和邏輯回歸後,完成kaggle網站的入門練習吧!
不知道kaggle是怎麼?大數據競賽平台——kaggle入門
註冊時遇到問題,親測有效:魏家輝:Kaggle賬號註冊時驗證碼無法顯示解決方法以及如何使用谷歌瀏覽器
1、初始數據
對「泰坦尼克號」的歷史很熟悉,項目背景就是預測乘客的生還率。換言之,形形色色的乘客,什麼樣的更有可能在這場災難中倖存?
稍微想一下,婦女兒童肯定優先吧,然後倉位、身份應該也有影響吧,看看源數據提供了哪些信息:
按照數值類型和類別類型,變數有:
數值:
PassengerId-乘客ID
Age-年齡
SibSp-堂兄弟姐妹個數
Parch-父母、小孩個數
Fare-船票價格
類別:
* Survive-是否生還,1生還,0死亡
Pclass-客艙等級,1頭等,2二等,3三等
Sex-性別,male、female
Embarked-登艙港口,S,C,Q
其他還有Name名字、Ticket船票編號、Cabin客艙編號,它們相對複雜。
其中Survive是標籤,其餘是特徵,我們的工作就是挖掘特徵與標籤之間的聯繫。
知道了數據意義,接下來必要地看一下數據完整度。將訓練集與測試集合併,一起處理提高效率:
#ignore_index=True,簡單地按列標籤拼接,不考慮索引問題full = train.append( test , ignore_index = True )
初步判斷Cabin缺失嚴重,Age、Fare有缺失,Survive是由於test里本來就缺少的,不用管它
2、數據清洗&探索
缺失值處理:
#Age缺失較多,但是年齡差距大,用平均值感覺沒什麼意義了,直接-10填充了full[Age] = full[Age].fillna(-10)#船票價格Fare用均值填充:full[Fare] = full[Fare].fillna(full[Fare].mean() )#Embarked只缺失兩個,用最高頻的「S」港口填充:#(還有一個原因是這兩個Embarked都來自頭等艙,頭等艙乘客從S港登艙最多)full[Embarked] = full[Embarked].fillna( S )#最後,Cabin的缺失實在太嚴重而且沒有參考值,用「U」填充代表未知 unknown:full[Cabin] = full[Cabin].fillna( U )
對年齡做離散化處理:
#離散處理#以5歲為一個周期離散,同時10以下,60歲以上的年分別歸類def age_map(x): if x<10: return 10- if x<60: return %d-%d%(x//5*5, x//5*5+5) elif x>=60: return 60+ else: return Nullfull[Age_map] = full[Age].apply(lambda x: age_map(x))#列印出來看看full.groupby(Age_map)[Survived].agg([count,mean])
3、特徵處理
一開始分析過類別變數,有3個取值是明確的:Pclass-客艙等級、Sex-性別、Embarked-登艙港口,為了建模方便,先把它們數值化。
對於「性別」,本身只有兩個取值,分別用0/1替代就可以了:
將性別的值映射為數值男(male)對應數值1,女(female)對應數值0sex_mapDict={male:1, female:0}#map函數:對Series每個數據應用自定義的函數計算train[Sex]=train[Sex].map(sex_mapDict)
對於兩個以上取值的變數,轉為虛擬變數,onehot一下。
稍微說一下虛擬變數(dummy variables)是什麼,以及如何產生,以港口Embarked為例,使用「get_dummies」函數會產生Embarked_C、Embarked_Q、Embarked_S三個虛擬變數來共同表示原本的Embarked取值,虛擬變數一般只取0或1:
#客艙等級#存放提取後的特徵,建立這個變數是為了之後聚合建模用的數據時更方便pclassDf = pd.DataFrame()#使用get_dummies進行one-hot編碼,列名前綴是PclasspclassDf = pd.get_dummies( full[Pclass] , prefix=Pclass )#刪除原變數full.drop(Pclass,axis=1,inplace=True)#登艙港口embarkedDf = pd.DataFrame()embarkedDf = pd.get_dummies( full[Embarked] , prefix=Embarked)full.drop(Embarked,axis=1,inplace=True)#年齡ageDf = pd.get_dummies(full[Age_map])full=pd.concat([full,ageDf],axis=1)
接下來還剩 Name、Cabin、Ticket,雖然是略複雜的字元串,也可以想想辦法提取出特徵,畢竟它們蘊含了豐富的信息!
- Cabin是客艙號,比如「C85」,取首字母代表客艙區域:
full[ Cabin ] = full[ Cabin ].map( lambda c : c[0] )#使用get_dummies進行one-hot編碼,列名前綴是Cabinfull = pd.concat([full,pd.get_dummies( full[Cabin] , prefix = Cabin )],axis=1)
得到了:
- Name,有人發現名字一定程度上能反映身份地位,尤其是外文裡帶有稱謂詞,比如Mrs、Miss、Dr,是個可以好好利用的線索!(服氣 ╯□╰ 要是我完全想不到呢 )
首先想辦法分離出name中的稱謂信息,觀察一下,是","和「.」中間的部分減掉一個空格:
定義函數:從姓名中獲取頭銜def getTitle(name): str1=name.split( , )[1] #Mr. Owen Harris str2=str1.split( . )[0]#Mr #strip() 方法用於移除字元串頭尾指定的字元(默認為空格) str3=str2.strip() return str3#存放提取後的特徵titleDf = pd.DataFrame()#map函數:對Series每個數據應用自定義的函數計算titleDf[Title] = full[Name].map(getTitle)
網上搜索一下,構建了一個稱謂&身份的映射,藉此生成身份虛擬變數:
定義以下幾種頭銜類別:Officer政府官員Royalty王室(皇室)Mr已婚男士Mrs已婚婦女Miss年輕未婚女子Master有技能的人/教師#姓名中頭銜字元串與定義頭銜類別的映射關係title_mapDict = { "Capt": "Officer", "Col": "Officer", "Major": "Officer", "Jonkheer": "Royalty", "Don": "Royalty", "Sir" : "Royalty", "Dr": "Officer", "Rev": "Officer", "the Countess":"Royalty", "Dona": "Royalty", "Mme": "Mrs", "Mlle": "Miss", "Ms": "Mrs", "Mr" : "Mr", "Mrs" : "Mrs", "Miss" : "Miss", "Master" : "Master", "Lady" : "Royalty" }titleDf[Title] = titleDf[Title].map(title_mapDict)titleDf = pd.get_dummies(titleDf[Title])full = pd.concat([full,titleDf],axis=1)full.drop(Name,axis=1,inplace=True)
好奇想瞅瞅有幾個皇室.....
- 家庭規模
數值變數里有兩個看起來不太熟悉的:SibSp和Parch。畫圖探究了一下,存活率隨家庭人數的變化先高後低,猜測是3口之家能互相幫助,求生機會大,但是人數過多又不再是優勢。。總之家庭規模值得作為一個參考特徵:
#存放家庭信息familyDf = pd.DataFrame()家庭人數=同代直系親屬數(Parch)+不同代直系親屬數(SibSp)+乘客自己familyDf[ FamilySize ] = full[ Parch ] + full[ SibSp ] + 1家庭類別:小家庭Family_Single:家庭人數=1中等家庭Family_Small: 2<=家庭人數<=4大家庭Family_Large: 家庭人數>=5#if 條件為真的時候返回if前面內容,否則返回0familyDf[ Family_Single ] = familyDf[ FamilySize ].map( lambda s : 1 if s == 1 else 0 )familyDf[ Family_Small ] = familyDf[ FamilySize ].map( lambda s : 1 if 2 <= s <= 4 else 0 )familyDf[ Family_Large ] = familyDf[ FamilySize ].map( lambda s : 1 if 5 <= s else 0 )familyDf.head()#添加one-hot編碼產生的虛擬變數(dummy variables)到泰坦尼克號數據集fullfull = pd.concat([full,familyDf],axis=1)full.head()
現在尾部又多了關於家庭規模的變數:
4、特徵選取
為了選取特徵可以探索性地查看各個變數與survive之間的關係,畫圖是最直觀的方法 , 下面「船票、年齡、存活」的散點圖,表現出15-50歲之間、低票價的乘客死亡率更高:
數據探索【這個案例】里分析得很好,畫了好多圖,參考他吧,本文略略略。。。(懶惰)
除了畫圖,可以藉助各特徵和標籤之間的相關性來判斷,計算相關係數:
查看各個特徵與生成情況(Survived)的相關係數,ascending=False表示按降序排列corrDf = full.corr() corrDf[Survived].sort_values(ascending =False)
根據排序,我選擇這幾個特徵建模~
#特徵選擇full_X = pd.concat( [titleDf,#頭銜 pclassDf,#客艙等級 familyDf,#家庭規模 full[Fare],#船票價格 cabinDf,#船艙號 embarkedDf,#登船港口 full[Sex],#性別 ageDf#年齡分布 ] , axis=1 )
5、建模
接下來我選擇邏輯回歸模型建模,生存或死亡,二選一用邏輯回歸是比較合適的!(我只會線性回歸和邏輯回歸。。。)
#原始數據集有891行sourceRow=891#原始數據集:特徵source_x = full_X.loc[0:sourceRow-1,:]#原始數據集:標籤source_y = full.loc[0:sourceRow-1,Survived] #預測數據集:特徵pred_x = full_X.loc[sourceRow:,:]from sklearn.cross_validation import train_test_split #建立模型用的訓練數據集和測試數據集train_x, test_x, train_y, test_y = train_test_split(source_x , source_y, train_size=.8)#第1步:導入演算法from sklearn.linear_model import LogisticRegression#第2步:創建模型:邏輯回歸(logisic regression)model = LogisticRegression()#第3步:訓練模型model.fit( train_X , train_y )#評估模型,score得到模型的正確率model.score(test_x , test_y )
我的模型正確率是0.84357541899441346。。。。
得嘞,把模型應用到預測集上,提交到kaggle
#使用機器學習模型,對預測數據集中的生存情況進行預測predict_y = model.predict(pred_x)生成的預測值是浮點數(0.0,1,0)但是Kaggle要求提交的結果是整型(0,1)所以要對數據類型進行轉換predict_y=predict_y.astype(int)#乘客idpassenger_id = full.loc[891:,PassengerId]#數據框:乘客id,預測生存情況的值predDf = pd.DataFrame( { PassengerId: passenger_id , Survived: predict_y } )predDf.shapepredDf.head()#保存結果predDf.to_csv( titanic_predict.csv , index = False )
這一篇真的是從模仿開始的...... 參考了
機器學習(入門):Kaggle和泰坦尼克號預測keep trying,看到好多前2%的大神啊。。我是個小透明,有空會再做一次兩次。
推薦閱讀:
※Zillow簡介(三)未來的成長空間有多大?
※怎麼著手玩kaggle?
※清華兩名博士從1萬名數據科學家中脫穎而出,獲得癌症檢測演算法頭名 ‖ 附冠軍團隊代碼
※【持續更新】機器學習特徵工程實用技巧大全
※Python員工離職預測
TAG:Kaggle |