機器學習入門:泰坦尼克號生存概率預測
機器學習的一般步驟:
1. 提出問題(Business Understanding )
2. 理解數據(Data Understanding)
* 採集數據
* 導入數據
* 查看數據集信息
3. 數據清洗(Data Preparation )
* 數據預處理
* 特徵工程(Feature Engineering)
4. 構建模型(Modeling)
5. 模型評估(Evaluation)
6. 方案實施 (Deployment)
* 提交結果到Kaggle
* 報告撰寫
1.項目背景
本文主要是對泰坦尼克號沉船事件進行預測:在當時的情況下,什麼樣的人更容易存活?
2.理解數據
2.1數據採集
本文所使用的數據是從Kaggle泰坦尼克號項目頁面下載的,下載鏈接如下:
Titanic: Machine Learning from Disaster在註冊kaggle的時候,郵箱驗證碼出現了問題,下面一起附解決問題的鏈接:
解決kaggle郵箱驗證不能confirm的問題 - CSDN博客2.2導入數據
# 忽略警告提示import warningswarnings.filterwarnings(ignore)#導入處理數據包import numpy as pyimport pandas as pd#訓練數據集train=pd.read_csv(./train.csv)#測試數據集test=pd.read_csv(./test.csv)#輸出數據print(訓練數據集:,train.shape,測試數據集:,test.shape)訓練數據集: (891, 12) 測試數據集: (418, 11)
從上面的代碼中可以看出,訓練數據共有891行,12列;測試數據共有418行,11列。測試數據少了生存情況那一列。
2.3查看數據信息
在查看數據信息之前,先把訓練數據和測試數據合併,這樣方便同時對數據進行清洗。
#合併數據集,方便同時對兩個數據集清洗full=train.append(test,ignore_index=True)print(合併後的數據集:,full.shape)合併後的數據集: (1309, 12)
查看前幾行數據:head
full.head()
查看數據集的描述統計信息:describe
full.describe()
describe只能查看數據類型的描述統計信息,對於其他類型的數據不顯示,比如字元串類型姓名(name),客艙號(Cabin).
查看每一行的數據信息和數據總數:info
full.info()
數據總共有1309行。
其中數據類型列:年齡(Age)、船票價格(Fare)裡面有缺失數據:
1)年齡(Age)裡面數據總數是1046條,缺失了1309-1046=263,缺失率263/1309=20%
2)船票價格(Fare)裡面數據總數是1308條,缺失了1條數據
字元串列:
1)登船港口(Embarked)裡面數據總數是1307,只缺失了2條數據,缺失比較少
2)船艙號(Cabin)裡面數據總數是295,缺失了1309-295=1014,缺失率=1014/1309=77.5%,缺失比較大。
這為我們下一步數據清洗指明了方向,只有知道哪些數據缺失數據,我們才能有針對性的處理。
3.數據清洗
3.1缺失值處理
1). 如果是數值類型,用平均值取代
2). 如果是分類數據,用最常見的類別取代
#年齡(Age)full[Age]=full[Age].fillna( full[Age].mean() )#船票價格(Fare)full[Fare] = full[Fare].fillna( full[Fare].mean() )#登船港口(Embarked)full[Embarked].value_counts()full[Embarked] = full[Embarked].fillna( S )#船艙號(Cabin),缺失數據比較多,船艙號(Cabin)缺失值填充為U,表示未知(Uknow) full[Cabin] = full[Cabin].fillna( U )#檢查數據處理是否正常full.head()
print(處理紅後:)full.info()
註:生成情況(Survived)這裡一列是我們的標籤,用來做機器學習預測的,不需要處理這一列
3.2特徵提取
數據分為:數值型數據、時間類型數據、分類數據。在分類數據中又有直接類別的(性別、登船港口、客艙等級)和字元串類型數據(姓名、客艙號、船票編號)。
對於直接類別數據來說:
性別
#sex#查看性別這一列的信息full[Sex].head()#將性別的值映射為數值:男(male)對應數值1,女(female)對應數值0sex_mapDict={male:1,feale:0}#map函數:對Series每個數據應用自定義的函數計算full[Sex]=full[Sex].map(sex_mapDict)full.head()
登船港口
#查看Embaeked信息full[Embarked].head()#存放提取後的特徵embarkedDf = pd.DataFrame()#使用get_dummies進行one-hot編碼,產生虛擬變數(dummy variables),列名前綴是EmbarkedembarkedDf = pd.get_dummies( full[Embarked] , prefix=Embarked )#添加one-hot編碼產生的虛擬變數(dummy variables)到泰坦尼克號數據集full = pd.concat([full,embarkedDf],axis=1)#把登船港口(Embarked)刪掉full.drop(Embarked,axis=1,inplace=True)full.head()
客艙等級
pclassDf = pd.DataFrame()pclassDf = pd.get_dummies( full[Pclass] , prefix=Pclass )full = pd.concat([full,pclassDf],axis=1)full.drop(Pclass,axis=1,inplace=True)full.head()#處理過程的代碼跟登船港口完全一樣,備註信息可參照登船港口
對於字元串信息來說:
姓名
#查看姓名這一列的信息full[ Name ].head()#練習從字元串中提取頭銜:split用於字元串分割,返回一個列表name1=Braund, Mr. Owen Harrisstr1=name1.split( , )[1] #Mr. Owen Harrisstr2=str1.split( . )[0]#Mr#strip() 方法用於移除字元串頭尾指定的字元(默認為空格)str3=str2.strip()#定義函數:從姓名中獲取頭銜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" }#map函數:對Series每個數據應用自定義的函數計算titleDf[Title] = titleDf[Title].map(title_mapDict)#使用get_dummies進行one-hot編碼titleDf = pd.get_dummies(titleDf[Title])#添加one-hot編碼產生的虛擬變數(dummy variables)到泰坦尼克號數據集fullfull = pd.concat([full,titleDf],axis=1)#刪掉姓名這一列full.drop(Name,axis=1,inplace=True)full.head()
客艙類別
# 定義匿名函數:對兩個數相加sum=lambda a,b:a+b#調用sum函數print(相加後的值:,sum(10,20))#查看客艙號信息full[Cabin].head()#存放客艙號信息cabinDf=pd.DataFrame()#客艙號類別值是首字母,例如C85類別映射為Cfull[Cabin]=full[Cabin].map(lambda C:C[0])#使用get_dummies進行one-hot編碼cabinDf=pd.get_dummies(full[Cabin],prefix=Cabin)#添加one-hot編碼產生的虛擬變數(dummy variables)到泰坦尼克號數據集中full=pd.concat([full,cabinDf],axis=1)#刪掉客艙這一列full.drop(Cabin,axis=1,inplace=True)full.head()
建立家庭人數和家庭類別
# 存放家庭信息familyDf=pd.DataFrame()#家庭人數=同代直系親屬數(Parch)+不同代直系親屬數(SibSp)+乘客自己#(因為乘客自己也是家庭成員的一個,所以這裡加1)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_Larage]=familyDf[FamilySize].map(lambda s:1 if 5<=s else 0)#添加one-hot編碼產生的虛擬變數(dummy variables)到泰坦尼克號數據集中full=pd.concat([full,familyDf],axis=1)full.head()
3.3特徵選擇
對特徵選擇不了解的話,可以學習下下面的資料:
機器學習之特徵工程
使用sklearn做單機特徵工程 - jasonfreak - 博客園
https://ahmedbesbes.com/how-to-score-08134-in-titanic-kaggle-challenge.html相關係數法:計算各個特徵的相關係數
#相關性矩陣corrDf = full.corr() corrDf
查看各個特徵與生成情況(Survived)的相關係數,ascending=False表示按降序排列corrDf[Survived].sort_values(ascending =False)
Survived 1.000000
Mrs 0.344935Miss 0.332795Pclass_1 0.285904Family_Small 0.279855
Fare 0.257307Cabin_B 0.175095Embarked_C 0.168240Cabin_D 0.150716Cabin_E 0.145321Cabin_C 0.114652Pclass_2 0.093349Master 0.085221Parch 0.081629Cabin_F 0.057935
Royalty 0.033391Cabin_A 0.022287FamilySize 0.016639Cabin_G 0.016040Embarked_Q 0.003650PassengerId -0.005007Cabin_T -0.026456Officer -0.031316SibSp -0.035322Age -0.070323Family_Large -0.125147Embarked_S -0.149683Family_Single -0.203367Cabin_U -0.316912Pclass_3 -0.322308Sex -0.543351Mr -0.549199Name: Survived, dtype: float64根據各個特徵與生成情況(Survived)的相關係數大小,我們選擇了這幾個特徵作為模型的輸入:
頭銜(前面所在的數據集titleDf)、客艙等級(pclassDf)、家庭大小(familyDf)、船票價格(Fare)、船艙號(cabinDf)、登船港口(embarkedDf)、性別(Sex)
full_X = pd.concat( [titleDf,#頭銜 pclassDf,#客艙等級 familyDf,#家庭大小 full[Fare],#船票價格 cabinDf,#船艙號 embarkedDf,#登船港口 full[Sex]#性別 ] , axis=1 )full_X.head()
4.構建模型
4.1 建立訓練數據集和測試數據集
#原始數據集有891行sourceRow=891sourceRow是我們在最開始合併數據前知道的,原始數據集有總共有891條數據從特徵集合full_X中提取原始數據集提取前891行數據時,我們要減去1,因為行號是從0開始的。#原始數據集:特徵source_X = full_X.loc[0:sourceRow-1,:]#原始數據集:標籤source_y = full.loc[0:sourceRow-1,Survived] #預測數據集:特徵pred_X = full_X.loc[sourceRow:,:]從原始數據集(source)中拆分出訓練數據集(用於模型訓練train),測試數據集(用於模型評估test)train_test_split是交叉驗證中常用的函數,功能是從樣本中隨機的按比例選取train data和test datatest_size:樣本佔比,如果是整數的話就是樣本的數量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)#輸出數據集大小print (原始數據集特徵:,source_X.shape, 訓練數據集特徵:,train_X.shape , 測試數據集特徵:,test_X.shape)print (原始數據集標籤:,source_y.shape, 訓練數據集標籤:,train_y.shape , 測試數據集標籤:,test_y.shape)
原始數據集特徵: (891, 27) 訓練數據集特徵: (712, 27) 測試數據集特徵: (179, 27)
原始數據集標籤: (891,) 訓練數據集標籤: (712,) 測試數據集標籤: (179,)4.2訓練模型:邏輯回歸模型
#導入演算法from sklearn.linear_model import LogisticRegressionmodel=LogisticRegression()model.fit(train_x,train_y)
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class=ovr, n_jobs=1, penalty=l2, random_state=None, solver=liblinear, tol=0.0001, verbose=0, warm_start=False)5.模型評估
model.score(test_x,test_y)
0.84357541899441346
第一次做項目正確率達到了84.36%,這個預測結果還可以在後面的學習中不斷的優化。
6.方案實施
pred_Y=model.predict(pred_X)pred_Y=pred_Y.astype(int)passenger_id=full.loc[sourceRow:,PassengerId]predDf=pd.DataFrame({PassengerId:passenger_id, Survived:pred_Y})predDf.head()
#保存結果predDf.to_csv(titanin_pred.csv,index=False)
上傳結果到Kaggle中,獲取排名:
推薦閱讀:
※tableau 學習,參考書籍
※「大數據」時代,什麼是數據分析做不了的?
※不同需求下可視化圖形選擇(翻譯)
※用戶與許可權(節選自《MySQL數據分析實戰》講義)
※推開數據分析的大門 (含2018年學習計劃)