好久沒更新了政鼠,由于疫情的原因,家里的工作一直比較忙队魏,最近閑下來了公般,學(xué)校也還沒開學(xué),正好趁著這段時間胡桨,復(fù)習(xí)一下前段時間的知識官帘,泰坦尼克號的案例在數(shù)據(jù)分析中是比較經(jīng)典的,今天我們就借助這個案例看一下數(shù)據(jù)分析的流程是怎么樣的昧谊。
一刽虹、數(shù)據(jù)集
首先我們先來看一下數(shù)據(jù)集,不要嘲笑我的中文路徑(哈哈哈)呢诬,當(dāng)初整理文件的時候嫌麻煩涌哲,直接上中文了,不過這里還是提醒一下大家馅巷,路徑盡量不要帶中文膛虫,以免有些代碼不支持。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('fivethirtyeight') # 樣式美化
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
data = pd.read_csv('../../數(shù)據(jù)集匯總/泰坦尼克號數(shù)據(jù)集/titanic_train.csv')
data.head()
這里我們分別看一下每個列名代表的含義:
- PassengerId: 乘客id
- Survived:是否獲救钓猬,0表示未獲救稍刀,1表示獲救
- Pclass:乘客等級(1/2/3等艙位)
- Name:乘客姓名
- Sex:性別
- Age:年齡
- SlbSp:堂兄弟/妹個數(shù)
- Parch:父母與小孩個數(shù)
- Ticket:船票信息
- Fare:票價
- Cabin:客艙
- Embarked:登船港口
數(shù)據(jù)集相對來說比較簡單,想要的特征基本上都給出來敞曹,簡單明了账月。
二、數(shù)據(jù)分析
數(shù)據(jù)集已經(jīng)知道各個字段的含義澳迫,接下來我們要進行數(shù)據(jù)分析局齿,看一下各個特征對結(jié)果的影響,統(tǒng)計繪圖得出結(jié)論橄登。
data.isnull().sum()
先來看一下抓歼,有沒有缺失值讥此,通過上圖可以看出,Age(年齡)谣妻、Cabin(客艙)和Embarked(登船港口)這三列存在缺失值萄喳,其中Cabin(客艙)的缺失值相對較多,由于這一列本身價值不高蹋半,后期我們會舍去他巨。
data.describe()
我們看一下具體的數(shù)據(jù)分布,通過
data.describe()
可以看到數(shù)據(jù)一共是891行减江,還可以看到一些列的最大最小值染突,比如年齡這一列,年齡最大的有80歲辈灼,最小的還不到一歲份企。
接下來,我們畫圖看一下茵休,
fig,ax = plt.subplots(1,2,figsize=(18,8))
# data['Survived'].value_counts().plot.pie(explode=[0,0.1],autopct='%1.1f%%',shadow=True,ax=ax[0])
ax[0].pie(data['Survived'].value_counts(),explode=[0,0.1],autopct='%1.1f%%',shadow=True,labels=[0,1])
ax[0].set_title('Survived')
ax[0].set_ylabel('')
sns.countplot('Survived',data=data,ax=ax[1])
ax[1].set_title('Survived')
plt.show()
通過餅圖可以看出來薪棒,獲救的占比才38.4%,一共有891個人榕莺,獲救的才300多一點,說明救援率還是比較低的棵介。
接下來我們對各個特征進行單獨分析钉鸯,看一下各個特征對結(jié)果的影響情況。
- 1邮辽、性別特征分析
data.groupby(['Sex','Survived'])['Survived'].count()
根據(jù)上面的統(tǒng)計分析可以看出唠雕,女性被救出來的幾率非常大,我們還可以畫圖看一下吨述,
fig,ax = plt.subplots(1,2,figsize=(10,8))
data[['Sex','Survived']].groupby(['Sex']).mean().plot.bar(ax = ax[0])
ax[0].set_title('Survived vs Sex')
sns.countplot(x='Sex',hue='Survived',data=data,ax=ax[1])
ax[1].set_title('Sex:Survived vs Dead')
plt.show
通過左圖可以看出岩睁,如果是女人,在所有的女人中有70%多的幾率會被救揣云,而男人只有20%不到(嗯...深刻的感受到了做男人的不易~)捕儒,右圖可以看出女性被救的人數(shù)比男性的兩倍還要多。通過分析發(fā)現(xiàn)邓夕,性別是一個重要的特征刘莹。
- 2、船艙等級特征分析
pd.crosstab(data.Pclass,data.Survived,margins=True).style.background_gradient(cmap='summer_r')
通過表格我們可以看出一等艙一共216人焚刚,有136人被救点弯,占比高于50%;二等艙有184人矿咕,87人被救抢肛,占比在50%左右狼钮;三等艙一共491人,只有119人被救捡絮,占比最低熬芜。雖然我們講生命不分貴賤,但是現(xiàn)實還是比較殘酷的锦援,有錢人被救的幾率還是遠(yuǎn)高于窮人猛蔽。
我們畫圖看一下,
fig,ax=plt.subplots(1,2,figsize=(10,8))
data['Pclass'].value_counts().plot.bar(color=['green','blue','yellow'],ax=ax[0])
ax[0].set_title('Number Of Passengers By Pclass')
sns.countplot('Pclass',hue='Survived',data=data,ax=ax[1])
ax[1].set_title('Pclass:Survived vs Dead')
plt.show()
兩圖對比更加明顯灵寺,一等艙被救的人數(shù)高于未被救的人數(shù)曼库,二等艙差不多,三等艙被救的人遠(yuǎn)低于未被救的人數(shù)略板。
我們再來看一下性別和船艙等級與被救之間的關(guān)系毁枯,
pd.crosstab([data.Sex,data.Survived],data.Pclass,margins=True).style.background_gradient(cmap='summer_r')
通過上表可以看出,在一等艙里叮称,女性被救的比例非常高种玛,女性一共有94人,91人被救瓤檐。
我們畫圖看一下男性與女性在各個船艙被救的比例赂韵,
sns.factorplot('Pclass','Survived',hue='Sex',data=data)
plt.show()
通過上圖可以看明顯看出,三個船艙中挠蛉,女性被救的比例遠(yuǎn)高于男性祭示。(心疼自己一秒鐘...)
-
3、年齡特征分析
先來看一下年齡的數(shù)值特征谴古,
print('最大年齡',data['Age'].max())
print('最小年齡',data['Age'].min())
print('平均年齡',data['Age'].mean())
# 輸出
最大年齡 80.0
最小年齡 0.42
平均年齡 29.69911764705882
接下來畫圖分析一下质涛,船艙等級和年齡、性別和年齡之間被救的關(guān)系掰担,
fig,ax = plt.subplots(1,2,figsize=(10,8))
sns.violinplot('Pclass','Age',hue='Survived',data=data,split=True,ax=ax[0])
ax[0].set_title('Pclass and Age vs Survived')
ax[0].set_yticks(range(0,110,10))
sns.violinplot('Sex','Age',hue='Survived',data=data,split=True,ax=ax[1])
ax[1].set_title('Sex and Age vs Survived')
ax[1].set_yticks(range(0,110,10))
plt.show()
通過左圖汇陆,可以分析出,一等艙被救的人中大部分集中在37带饱、8歲左右毡代,二等艙被救的人大部分集中在30歲,三等艙集中在20 ~ 30歲左右纠炮,可以看出一等艙被救的年齡比其他兩個艙的要大月趟,有可能是一等艙本身就是比較富有的人,一般都是拼搏到了一定的年齡才會這樣(瞎猜的);右圖的話,可以看出男性被救的年齡在30歲左右尉辑,女性被救的20~30歲左右浑测,差距不是很大呀闻。
- 4躺翻、登船地點特征分析
pd.crosstab([data.Embarked,data.Pclass],[data.Sex,data.Survived],margins=True).style.background_gradient(cmap='summer_r')
通過圖表可以看出鸠项,S登船地的人數(shù)最多饼暑,Q最少婚被。
sns.factorplot('Embarked','Survived',data=data)
fig=plt.gcf()
fig.set_size_inches(5,3)
通過上圖可以看出狡忙,C港的生存率最高,在0.55左右址芯,而S港的生存率最低灾茁。(莫名的想起吃雞~)
fig,ax=plt.subplots(2,2,figsize=(15,15))
sns.countplot('Embarked',data=data,ax=ax[0][0])
ax[0][0].set_title('No. Of Passengers Boarded')
sns.countplot('Embarked',hue='Sex',data=data,ax=ax[0][1])
ax[0][1].set_title('Male-Femal Split for Embarked')
sns.countplot('Embarked',hue='Survived',data=data,ax=ax[1][0])
ax[1][0].set_title('Embarked vs Survived')
sns.countplot('Embarked',hue='Pclass',data=data,ax=ax[1][1])
ax[1][1].set_title('Embarked vs Pclass')
plt.subplots_adjust(wspace=0.2,hspace=0.5)
plt.show()
左上,登船地點的人數(shù)統(tǒng)計谷炸,可以明顯看出S港最多北专;右上,各個登船地點的男女人數(shù)統(tǒng)計旬陡;左下拓颓,各個登船地點獲救與未獲救的人數(shù)統(tǒng)計,結(jié)合上表描孟,S港的獲救人數(shù)最高驶睦,但是獲救占比卻是最低的;右下匿醒,各個登船地點的船艙等級人數(shù)統(tǒng)計场航,可以看出S港登船的人數(shù)最多,其中三等艙的人數(shù)最多廉羔,Q港幾乎沒有一等艙的人登船旗闽。
sns.factorplot('Pclass','Survived',hue='Sex',col='Embarked',data=data)
plt.show()
上圖是各個登船地點,每個船艙等級被救的男女比例蜜另,總之完全符合女人和孩子第一的政策。
- 5嫡意、堂兄弟/妹特征分析
pd.crosstab(data.Survived,data.SibSp,margins=True).style.background_gradient(cmap='summer_r')
plt.figure(figsize=(8,8))
sns.countplot('SibSp',hue='Survived',data=data)
plt.show()
通過上圖表可以看出举瑰,堂兄弟/妹個數(shù)越多,基數(shù)越少蔬螟,被救的也就越少此迅,所以我們就簡單分析一下,保留這個特征旧巾。
- 6耸序、父母與小孩個數(shù)特征分析
pd.crosstab(data.Survived,data.Parch,margins=True).style.background_gradient(cmap='summer_r')
plt.figure(figsize=(8,8))
sns.countplot('Parch',hue='Survived',data=data)
plt.show()
這個特征與堂兄弟/妹個數(shù)的特征相似,父母孩子個數(shù)越多鲁猩,基數(shù)越少坎怪,被救的人數(shù)也越少。比如有父母或孩子4廓握、5個的人很少搅窿,都沒有被救嘁酿,這個特征我們也保留。
以上就是我們對各個特征之間的理解男应,還有幾個特征比如Ticket
(船票信息)闹司、Cabin
(客艙)等我們沒有進行分析,主要原因是船票信息對是否獲救意義不大沐飘,而客艙Cabin
缺失值較多游桩,這些信息在接下來的數(shù)據(jù)處理中我們直接刪掉了。
三耐朴、數(shù)據(jù)清洗與預(yù)處理
1借卧、缺失值填充
首先我們先處理一下缺失值,通過上面的data.isnull().sum()
我們知道有兩個特征值存在缺失的情況(Cabin
不考慮)隔箍。
-
Age年齡問題
關(guān)于年齡填充谓娃,我們一般是選擇年齡的平均值進行填充,但是這里我們發(fā)現(xiàn)蜒滩,在Name
這一列滨达,名字都比較長,中間會帶有Mr,Miss,Mrs
等特征來標(biāo)識每一個人俯艰,我們可以根據(jù)這個特點捡遍,求出每個標(biāo)識中,年齡的平均值進行填充竹握,這樣填充的效果會更加實際画株。
# 先用正則表達(dá)式進行提取
data['initial'] = 0
for i in data:
data['initial']=data.Name.str.extract('([A-Za-z]+)\.')
data.head()
接下來我們看一下分出來的男女人數(shù),
pd.crosstab(data.initial,data.Sex).T.style.background_gradient(cmap='summer_r')
我們將人數(shù)比較多的提取出來啦辐,剩下的用
others
代替谓传,
data['initial']=data['initial'].replace(['Capt','Col','Countess','Don','Dr','Jonkheer','Lady','Major','Master','Mlle','Mme','Ms','Rev','Sir'],'others')
接下來,我們求出每個標(biāo)識的平均年齡芹关,
data.groupby('initial')['Age'].mean()
最后我們可以填充了续挟,
data.loc[(data.Age.isnull())&(data.initial == 'Miss'),'Age']=22
data.loc[(data.Age.isnull())&(data.initial == 'Mr'),'Age']=32
data.loc[(data.Age.isnull())&(data.initial == 'Mrs'),'Age']=36
data.loc[(data.Age.isnull())&(data.initial == 'others'),'Age']=20
我們還可以畫圖展示一下,
fig,ax = plt.subplots(1,2,figsize=(10,8))
data[data['Survived']==0].Age.plot.hist(ax=ax[0],bins=20,edgecolor='black',color='red')
ax[0].set_title('Survived = 0')
data[data['Survived']==1].Age.plot.hist(ax=ax[1],bins=20,edgecolor='black',color='green')
ax[1].set_title('Survived = 1')
plt.show()
通過上圖可以看到侥衬,被救最多人的的年齡分布在20~40之間诗祸,超過60歲的被救的比較少了(年齡最大的人(80歲)被救了)。
-
Embarked缺失值填充
Embarked
列的缺失值填充比較簡單轴总,通過上面的特征分析我們可以發(fā)現(xiàn)直颅,S港的人數(shù)最多,所以我們就用眾數(shù)填充怀樟,
data['Embarked'].fillna('S',inplace=True)
填充完畢后功偿,我們再統(tǒng)計一下缺失值,
data.isnull().sum()
就只剩
Cabin
列漂佩,接下我們進行數(shù)據(jù)預(yù)處理脖含。
2罪塔、數(shù)據(jù)預(yù)處理
首先我們先將沒用的特征進行處理,
data=data.drop(['Name','Ticket','Cabin','initial'],axis=1)
data.head()
接下來我們將性別特征和登船港口數(shù)字化养葵,因為接下來用到的算法沒法處理文字征堪,
#將性別數(shù)字化,male=0,female=1
data.loc[data['Sex']=='male','Sex']=0
data.loc[data['Sex']=='female','Sex']=1
# 登船港口數(shù)字化 S=0,C=1,Q=2
data.loc[data['Embarked']=='S','Embarked']=0
data.loc[data['Embarked']=='C','Embarked']=1
data.loc[data['Embarked']=='Q','Embarked']=2
data.head()
四关拒、建立模型
這里我們使用多個機器學(xué)習(xí)算法進行預(yù)測佃蚜,看一下效果如何。
1着绊、線性回歸預(yù)測
將訓(xùn)練集劃分出特征和標(biāo)簽
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold
linear = LinearRegression()
features = ['Pclass','Sex','Age','SibSp','Parch','Fare','Embarked']
kf=KFold(n_splits=3,shuffle=False,random_state=1)
source_x = data[features] # 訓(xùn)練數(shù)據(jù)集:特征
source_y = data['Survived'] #訓(xùn)練數(shù)據(jù)集:標(biāo)簽
source_x.shape
#輸出
(891,7)
將數(shù)據(jù)集劃分為訓(xùn)練集和測試集谐算,
from sklearn.model_selection import train_test_split
train_x,test_x,train_y,test_y = train_test_split(source_x,source_y,train_size=0.8)
print('原始數(shù)據(jù)集特征:',source_x.shape,'訓(xùn)練集特征:',train_x.shape,'測試集特征',test_x.shape)
# 輸出
原始數(shù)據(jù)集特征: (891, 7) 訓(xùn)練集特征: (712, 7) 測試集特征 (179, 7)
進行模型訓(xùn)練,
linear.fit(train_x,train_y)
linear.score(test_x,test_y)
準(zhǔn)確率太低了归露,不知道哪里出了問題洲脂。
接下來,我們進行交叉驗證再試一下剧包,
# K折交叉驗證
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold
# from sklearn.model_selection import cross_val_score
model = LinearRegression()
kf = KFold(n_splits=3,shuffle=False,random_state=1)
# scores = cross_val_score(model,source_x,source_y,cv=kf)
# scores.mean()
scores=[]
for train,test in kf.split(source_x):
train_data = source_x.iloc[train,:]
train_target = source_y.iloc[train]
model.fit(train_data,train_target)
test_data = model.predict(source_x.iloc[test,:])
scores.append(test_data)
因為結(jié)果只有0和1恐锦,而我們預(yù)測的結(jié)果分布在[0,1]區(qū)間上,所以我們將預(yù)測的得分值超過0.5設(shè)為1疆液,小于0.5的設(shè)為0一铅,
import numpy as np
scores = np.concatenate(scores,axis=0)
scores[scores>.5]=1
scores[scores<.5]=0
accuracy = sum(scores==source_y)/len(source_y)
print(accuracy)
準(zhǔn)確率提高了不少。
2堕油、邏輯斯蒂回歸預(yù)測
LR雖然是回歸算法潘飘,但是也可以做分類的,這里我們也進行了交叉驗證掉缺,
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(random_state=1)
scores = cross_val_score(model,source_x,source_y,cv=3)
print(scores.mean())
準(zhǔn)確率也有所提升卜录。
3、隨機森林預(yù)測
# 隨機——隨機對樣本進行采樣
# 隨機——對特征進行隨機抽取
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(random_state=1,
n_estimators=200,#200課樹
min_samples_split=4,
min_samples_leaf=2)
kf = KFold(n_splits=3,shuffle=False,random_state=1)
scores = cross_val_score(model,source_x,source_y,cv=kf)
print(scores.mean())
隨機森林還是比較強的眶明,結(jié)果也有所提升暴凑。
4、集成算法
集成算法是將幾個算法合并在一起進行預(yù)測的算法赘来,在生產(chǎn)實際和各種比賽都被廣泛應(yīng)用;隨機森林也是一種集成算法凯傲,它由多個決策樹合并在一起進行決策犬辰,這里我們將隨機森林與邏輯斯蒂回歸算法進行合并,看一下效果如何冰单。
features = ['Pclass','Sex','Age','SibSp','Parch','Fare','Embarked']
model = RandomForestClassifier(random_state=1,
n_estimators=200,#100課樹
min_samples_split=8,
min_samples_leaf=4)
from sklearn.ensemble import GradientBoostingClassifier
import numpy as np
#定義兩個算法集成在一起
algorithms = [
[GradientBoostingClassifier(random_state=1,n_estimators=200,max_depth=3),features],
[LogisticRegression(random_state=1,solver='liblinear'),features]
]
kf=KFold(n_splits=3,shuffle=False,random_state=1)
predictions=[]
for train,test in kf.split(source_x):
train_target = source_y.iloc[train]
full_test_predictions = []
for alg,predictors in algorithms:
alg.fit(source_x.iloc[train,:],train_target)
test_predictions = alg.predict_proba(source_x.iloc[test,:].astype(float))[:,1]
full_test_predictions.append(test_predictions)
test_predictions = (full_test_predictions[0]+full_test_predictions[1])/2
test_predictions[test_predictions <=.5] =0
test_predictions[test_predictions >.5] =1
predictions.append(test_predictions)
predictions = np.concatenate(predictions,axis=0)
accuracy = sum(predictions == source_y)/len(predictions)
print(accuracy)
可以看到效果也是不錯幌缝,跟隨機森林的準(zhǔn)確率差不多。
五诫欠、總結(jié)
算法預(yù)測到這里就結(jié)束了涵卵,如果小伙伴有其他的想法可以自行測試浴栽,這里其實還是有很多可以改變的地方,比如轿偎,對于Name
列典鸡,一般名字比較長的屬于大家族,比較富有坏晦,可以統(tǒng)計一下名字的長度作為一個特征萝玷;在提取Mr,Miss,Mrs等
標(biāo)識時也可以使用one-hot編碼
進行處理,這樣獲得特征就會增加很多昆婿;還可以將堂兄弟/妹和父母孩子個數(shù)做一個求和添加一個Family
的特征...這些都是可以的球碉,感興趣的同學(xué)可以嘗試一下。
最后我們總結(jié)一下數(shù)據(jù)挖掘的一般流程:
1仓蛆、數(shù)據(jù)讀取
- 讀取數(shù)據(jù)睁冬,并進行展示
- 統(tǒng)計數(shù)據(jù)各項指標(biāo)
- 明確數(shù)據(jù)規(guī)模與要完成的任務(wù)
2、特征理解分析
- 單特征分析看疙,逐個變量分析其對結(jié)果的影響
- 多變量統(tǒng)計分析豆拨,綜合考慮多種情況影響
- 統(tǒng)計繪圖得出結(jié)論
3、數(shù)據(jù)清洗與預(yù)處理
- 對缺失值進行填充
- 特征標(biāo)準(zhǔn)化/歸一化
- 篩選有價值的特征
- 分析特征之間的相關(guān)性
4狼荞、建立模型
- 特征數(shù)據(jù)與標(biāo)簽準(zhǔn)備
- 數(shù)據(jù)集切分
- 多種建模算法對比
- 集成策略等方案改進
好了辽装,今天的學(xué)習(xí)到這里就結(jié)束了~