泰坦尼克号的沉没是世界上最严重的海滩事故之一,通过模型来预测哪些人可能成为幸存者。
1、导入基本所需的库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
plt.style.use('fivethirtyeight')
import warnings
warnings.filterwarnings('ignore')
2、导入数据集,探索数据
data = pd.read_csv('train.csv')
data.head()
离散型的变量有:Survived,Sex 和 Embarked。基于序列的有:Pclass
连续型的数值特征有:Age,Fare。离散型数值有:SibSp,Parch
混合型变量:Ticket和Cabin
Name的特征可能包含错误或者打字错误
data.isnull().sum()
这些特征包含null值的数量大小为:Cabin > Age > Embarked
data.info()
有7个特征是int型或float 型
有5个特征是object类型
#数值型特征的数值分布
data.describe()
#离散型数据的分布
data.describe(include=['object'])
# 标签比例 获救比例情况
f,ax = plt.subplots(1,2,figsize=(10,6))
data['Survived'].value_counts().plot.pie(explode=[0,0.1],
autopct='%1.1f%%',
ax=ax[0],shadow=True)
ax[0].set_title('Survived')
sns.countplot('Survived',data=data,ax=ax[1])
3、特征分析
# 标签比例 获救比例情况
f,ax = plt.subplots(1,2,figsize=(10,6))
data['Survived'].value_counts().plot.pie(explode=[0,0.1],
autopct='%1.1f%%',
ax=ax[0],shadow=True)
ax[0].set_title('Survived')
sns.countplot('Survived',data=data,ax=ax[1])
# 不同性别下存活人数
data.groupby(['Sex','Survived'])['Survived'].count()
sns.countplot('Sex',hue='Survived',data=data)
# Pclass和获救之间的关系
pd.crosstab(data.Pclass,data.Survived,margins=True).style.background_gradient(cmap='GnBu_r')
sns.countplot('Pclass',hue='Survived',data=data)
#数值型特征age与Survived之间的联系
g = sns.FacetGrid(data, col='Survived')
g.map(plt.hist, 'Age', bins=20)
plt.show()
婴儿(Age<=4)有较高的生存率(20个bin,每个bin为4岁)
老人(Age=80)全部生还
大量的15-25年纪的乘客没有生还
乘客主要在15-35的年纪范围内
#不同性别下不同船舱存活情况
pd.crosstab([data.Sex,data.Survived],data.Pclass,margins=True) #pclass在纵轴
sns.factorplot('Pclass','Survived',hue='Sex',data=data) #三维数据压成二维画图
女性乘客相对于男性乘客有着更高的存活率
pclass=1 存活率更高
#分析不同embarked港口和船舱等级
sns.countplot('Embarked',hue='Pclass',data=data)
#查看Embarked(离散非数值型),Sex(离散非数值型),Fare(连续数值型)与Survived(离散数值型)之间的关系
grid = sns.FacetGrid(data, row='Embarked', col='Survived', size=2.2, aspect=1.6)
grid.map(sns.barplot, 'Sex', 'Fare', order=data.Sex.unique(),alpha=.5, ci=None)
grid.add_legend()
plt.show()
付了高票价的乘客有着更高的生存率
Embarked与生存率相关
5、缺失值填充
# 通过提取name中的称谓对应age的区间,来填补age缺失值
data['initial'] = data.Name.str.extract('([A-Za-z]+)\.') #正则表达式提取
data['initial']
pd.crosstab(data.initial,data.Sex).T
#人数很少的称谓都替换成other
re=[]
for i in data.initial.values:
if i!='Master' and i!='Miss' and i!='Mr' and i!='Mrs':
re.append(i.replace(i,'other'))
else:
re.append(i)
#称谓和存活的关系
sns.countplot('re',hue='Survived',data=data)
#计算每一个称谓所对应的的年龄的均值
data.groupby('re')['Age'].mean()
#用循环实现将年龄的均值转化为整数并且填补
for i in data.re.values:
data.loc[(data.Age.isnull())&(data.re==i),'Age']=int(data.groupby('re')['Age'].mean()[i])
#检查是否填充完毕
data.Age.isnull().sum()
#填补Embarked 用众数填
data['Embarked'].fillna('S',inplace=True)
6、数据预处理
#Age离散化
data['Age_band']=0
data.loc[data['Age']<=16,'Age_band']=0
data.loc[(data['Age']>16)&(data['Age']<=32),'Age_band']=1
data.loc[(data['Age']>32)&(data['Age']<=48),'Age_band']=2
data.loc[(data['Age']>48)&(data['Age']<=65),'Age_band']=3
data.loc[data['Age']>65,'Age_band']=4
data.head(1)
#将类别 数值化Sex、Embarked、re
from sklearn import preprocessing #导入数据预处理模块
lbl = preprocessing.LabelEncoder() #标签编码 实例化
data['Sex']=lbl.fit_transform(data['Sex'])
data['Embarked']=lbl.fit_transform(data['Embarked'])
data['re']=lbl.fit_transform(data['re'])
#港口无大小关系,但编码后有大小关系,需要处理(哑变量)
data['Embarked'].unique()
one_hot=preprocessing.OneHotEncoder(sparse=False) #独热编码 实例化 sparse=false不会升维
data['Embarked']=one_hot.fit_transform(data[['Embarked']]) #使用独热编码 必须是数值类型,字符类型不能直接做。其中必须 fit 二维数据,因此data两层中括号
#组合Parch和SibSp特征,创建一个新的FamilySize特征
data['FamilySize'] = data['SibSp'] + data['Parch'] + 1
data[['FamilySize', 'Survived']].groupby(['FamilySize'], as_index=False).mean().sort_values(by='Survived', ascending=False)
#创建另一个名为IsAlone的特征
data['IsAlone'] = 0
data.loc[data['FamilySize'] == 1, 'IsAlone'] = 1
data[['IsAlone', 'Survived']].groupby(['IsAlone'], as_index=False).mean()
一个人存活率低
#将Fare分段
data['FareBand'] = pd.qcut(data['Fare'], 4)
data[['FareBand', 'Survived']].groupby(['FareBand'], as_index=False).mean().sort_values(by='FareBand', ascending=True)
#分段后的特征FareBand,将Fare转换为有序的数值型特征
lbl = preprocessing.LabelEncoder()
data['FareBand']=lbl.fit_transform(data['FareBand'])
data['Age_band*Class'] = data.Age_band * data.Pclass
data.loc[:, ['Age_band*Class', 'Age_band', 'Pclass']].head(10)
#删除无用列
data.drop(['PassengerId','Name','Age','Ticket','Fare','Cabin','initial','FamilySize','SibSp','Parch'],axis=1,
inplace=True)
# 相关性热图
sns.heatmap(data.corr(),annot=True,linewidths=0.2,cmap='summer_r') #data.corr()返回相关性的值
fig = plt.gcf() #建立画布
fig.set_size_inches(8,6) #画布尺寸
from sklearn.neighbors import KNeighborsClassifier #knn算法
from sklearn.tree import DecisionTreeClassifier #决策树
from sklearn.naive_bayes import GaussianNB #高斯贝叶斯
from sklearn.linear_model import LogisticRegression #逻辑回归
from sklearn.ensemble import RandomForestClassifier #随机森林
from sklearn.model_selection import train_test_split #划分数据集
X = data.iloc[:,data.columns!='Survived']
y = data.iloc[:,data.columns=='Survived']
Xtrain,Xtest,Ytrain,Ytest=train_test_split(X,y,test_size=0.2,
random_state=10)
逻辑回归
# 逻辑回归
logreg = LogisticRegression()
logreg.fit(Xtrain, Ytrain)
Y_pred = logreg.predict(Xtest)
acc_log = round(logreg.score(Xtrain, Ytrain) * 100, 2)
acc_log
#77.67
KNN
score=[]
for i in list(range(1,11)):
KNN = KNeighborsClassifier(n_neighbors=i)
CVS = cross_val_score(KNN,Xtrain,Ytrain,cv=5) #交叉验证
score.append(CVS.mean())
plt.plot([*range(1,11)],score) # *range 激活成列表
fig = plt.gcf()
fig.set_size_inches(12,6)
#最优k=7
knn = KNeighborsClassifier(n_neighbors = 7)
knn.fit(Xtrain, Ytrain)
Y_pred = knn.predict(Xtest)
acc_knn = round(knn.score(Xtrain, Ytrain) * 100, 2)
acc_knn
#82.58
朴素贝叶斯
gaussian = GaussianNB()
gaussian.fit(Xtrain, Ytrain)
Y_pred = gaussian.predict(Xtest)
acc_gaussian = round(gaussian.score(Xtrain, Ytrain) * 100, 2)
acc_gaussian
#73.6
决策树
#网格搜索
from sklearn.model_selection import GridSearchCV
# 设置可选参数
param_grid = {
'criterion':['entropy','gini'],
'max_depth':range(2,10),
'min_samples_leaf':range(1,10),
'min_samples_split':range(2,10)}
# 设置网格
GR = GridSearchCV(DecisionTreeClassifier(),param_grid,cv=5)
# 建模
GR.fit(Xtrain,Ytrain)
# 输出接口 最优的取值
GR.best_params_
#{'criterion': 'entropy', 'max_depth': 8, 'min_samples_leaf': 3,'min_samples_split': 9}
decision_tree = DecisionTreeClassifier(criterion='entropy',max_depth=8,
min_samples_leaf=3,min_samples_split=9).fit(Xtrain,Ytrain)
decision_tree.fit(Xtrain, Ytrain)
Y_pred = decision_tree.predict(Xtest)
acc_decision_tree = round(decision_tree.score(Xtrain, Ytrain) * 100, 2)
acc_decision_tree
#84.13
使用决策树的算法使得正确率达到了一个更高的值
#特征重要性可视化
decision_tree.feature_importances_
pd.Series(decision_tree.feature_importances_,X.columns).sort_values(ascending=True).plot.barh(width=0.8)
随机森林
random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(Xtrain, Ytrain)
Y_pred = random_forest.predict(Xtest)
acc_random_forest = round(random_forest.score(Xtrain, Ytrain) * 100, 2)
acc_random_forest
#85.96
9、模型评价
models = pd.DataFrame({
'Model': [ 'KNN','Logistic Regression','GaussianNB',
'Random Forest','Decision Tree'],
'Score': [acc_knn,acc_log,acc_gaussian,
acc_random_forest,acc_decision_tree]})
models.sort_values(by='Score', ascending=False)
其中决策树与随机森林的正确率最高,但是我们在这里会选择随机森林算法,因为它相对于决策树来说,弥补了决策树有可能过拟合的问题。