问题初识
这个题目的背景概况来讲就是基于泰坦尼克号这个事件,然后大量的人员不幸淹没在这个海难中,也有少部分人员在这次事件之中存活,然后这个问题提供了一些人员的信息如姓名、年龄、性别、票价,所在客舱等等一些信息,和是否获救,然后你建模分析,去预测另一批乘客的获救与否,然后得出的结果进行评价,预测率较高的,匹配率较好的分数就比较高。这个问题的数据集都可以在kaggle上面下下来。接下来就不多说了,开始摸索。(ps:题主也是入门级的,本文出现的问题也恳请广大小友提出交流)
开始操作
1.首先我们先来看一下我们得到的训练数据都包含哪些东西
##这里我们导入相关需要的库
import numpy as np
import pandas as pd
from IPython.display import display
%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
##这里我们导入并展示训练数据和测试数据
##导入训练数据
train=pd.read_csv('train.csv')
##导入测试数据
test=pd.read_csv('test.csv')
##展示第一行数据
display(train.head(n=1),test.head(n=1))
运行结果看出来训练集中包含的标签大致如下
- PassengerId -> 乘客ID
- Pclass -> 乘客等级(1/2/3等舱位)
- Name -> 乘客姓名
- Sex -> 性别
- Age -> 年龄
- SibSp -> 堂兄弟/妹个数
- Parch -> 父母与小孩个数
- Ticket -> 船票信息
- Fare -> 票价
- Cabin -> 客舱
- Embarked -> 登船港口
在测试集里面我们展示的结果:
我们可以看出来训练集比测试集多了一个survied存活标签
##查看训练数据
train.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId 891 non-null int64
Survived 891 non-null int64
Pclass 891 non-null int64
Name 891 non-null object
Sex 891 non-null object
Age 714 non-null float64
SibSp 891 non-null int64
Parch 891 non-null int64
Ticket 891 non-null object
Fare 891 non-null float64
Cabin 204 non-null object
Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB
从上面的数据展示可以看出来,有11个特征, 其中Age,Cabin,Embarked,有缺失值,我们处理缺失值的做法先考虑以下几种
1.直接删除此特征
2.直接删除缺损数据的样本
3.直接将有无数值作为新的特征
4.中值或均值回补
5.参考其他特征,利用与此特征的相关性编写算法回补数据
从上面的11个特征中,我们进行分析,首先特征PassengerId 乘客的id 个人感觉这个与我们进行预测没多大关系,这里我们删除它
然后看Pclass 表示乘客票务仓,也即区分阶层的一个东西,这个应该很有用,我们用seaborn绘图函数库作可视化分析,来观察一下
sns.countplot(x="Pclass", hue="Survived", data=train)
结果如下
从上图我们可以看出,船舱1,2,3的等级,它们的存活率差异还是比较明显的
然后我们看sex性别这个
画图展示
sns.countplot(x="Sex", hue="Survived", data=train)
从上图可以看出,sex中女性的存活率还是比男性高的,sex这个特征是一重要特征
然后我们在看age这个特征,这个特征是连续的,并且有缺失值,我们考虑如何处理
首先我们用密度图看看Age这个特征与生还率的关系怎样
facet = sns.FacetGrid(train, hue="Survived",aspect=2) ##画出轮廓,设置参数hue分类
facet.map(sns.kdeplot,'Age',shade= True) ##填充,密度估计图
facet.set(xlim=(0, train['Age'].max())) ##设定x轴上下限
facet.add_legend() ##加注释
##x,y坐标分别是
plt.xlabel('Age')
plt.ylabel('density')
不同生还情况的密度图可以看出,在年龄12岁的左侧,生还率有明显差别,12岁以下的存活率比较高
而在12到30岁之间死亡率还是比较高的,30-60岁之间存活率和死亡率大致相当,60-75岁死亡率又稍稍上升,75岁以上基本存活
那么我们可以将年龄这个特征分为6类,12以下,12-30,30-60,60-78,75以上,和没数据的。
#年龄特征分类
train=pd.read_csv('train.csv')
train['Age']=train['Age'].map(lambda x: 'child' if x<12 else 'youth' if x<30 else 'adlut'
if x<60 else 'old' if x<75 else 'tooold' if x>=75 else 'null')
##然后我们看SibSp,表示配偶及兄弟姐妹个数,这个特征可能会有影响
##做个图看看
sns.countplot(x="SibSp", hue="Survived", data=train)
##从上图可以看出属性1的情况下存活率较高,为0的存活率较低,
##我们将其分为三类
train['SibSp']=train['SibSp'].map(lambda x: 'small' if x<1 else 'middle' if x<3 else 'large')
##然后我们看Parch,表示父母与子女数,看图说话
sns.countplot(x="Parch", hue="Survived", data=train)
##从上图我们可以看出,结果和SibSp的类似,我们也把其分为三类
train['Parch']=train['Parch'].map(lambda x: 'small' if x<1 else 'middle' if x<4 else 'large')
##然后我们在来看Ticket表示船票号,个人感觉没太大关系,好像画图也比较麻烦,先放一边
##然后看Fare票价,这个东东应该会有较大关系的,做个图
facet = sns.FacetGrid(train, hue="Survived",aspect=2) ##画出轮廓,设置参数hue分类
facet.map(sns.kdeplot,'Fare',shade= True) ##填充,密度估计图
facet.set(xlim=(0, train['Fare'].max())) ##设定x轴上下限
facet.add_legend()
plt.xlabel('Fare')
plt.ylabel('density')
##从上图中我们可以看出低票价的明显存活率较低,高票价的存活率较高。
##我们这里设为两类
train['Fare']=train['Fare'].map(lambda x1: 'poor' if x1<10 else 'rich')
##我们再看Cabin表示客舱,数据缺失太多
#有编号的的为yes,没有的为no
train['Cabin']=train['Cabin'].map(lambda x:'yes' if type(x)==str else 'no')
#作图
sns.countplot(x="Cabin", hue="Survived", data=train)
##然后我们看Embarked这个表示船舶停靠港口
##画图看看有什么相关性
sns.countplot(x="Embarked", hue="Survived", data=train)
##从图中明显分为三类
#删掉含有缺损值的样本
train.dropna(axis=0,inplace=True)
#查看训练集的信息
train.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 889 entries, 0 to 890
Data columns (total 12 columns):
PassengerId 889 non-null int64
Survived 889 non-null int64
Pclass 889 non-null int64
Name 889 non-null object
Sex 889 non-null object
Age 889 non-null object
SibSp 889 non-null object
Parch 889 non-null object
Ticket 889 non-null object
Fare 889 non-null object
Cabin 889 non-null object
Embarked 889 non-null object
dtypes: int64(3), object(9)
memory usage: 90.3+ KB
#将训练数据分成标记和特征两部分
labels= train['Survived'] ##标记集
features= train.drop(['Survived','PassengerId','Name','Ticket'],axis=1) ##删除这几列
#对所有特征实现独热编码
features = pd.get_dummies(features) ##特征值提取
encoded = list(features.columns)
print ("{} total features after one-hot encoding.".format(len(encoded)))
22 total features after one-hot encoding.
#对'Age','SibSp','Parch'特征进行分段分类
test['Age']=test['Age'].map(lambda x: 'child' if x<12 else 'youth' if x<30 else 'adlut' if x<60 else 'old' if x<75 else 'tooold' if x>=75 else 'null')
test['SibSp']=test['SibSp'].map(lambda x: 'small' if x<1 else 'middle' if x<3 else 'large')
test['Parch']=test['Parch'].map(lambda x: 'small' if x<1 else 'middle' if x<4 else 'large')
#均值补齐'Fare'特征值并作对数转换和分类
test.Fare.fillna(test['Fare'].mean(), inplace=True)
test['Fare']=test['Fare'].map(lambda x: 'poor' if x<10 else 'rich')
#按'Cabin'是否缺损分类
test['Cabin']=test['Cabin'].map(lambda x:'yes' if type(x)==str else 'no')
#删除不需要的特征并进行独热编码
Id=test['PassengerId']
test=test.drop(['PassengerId','Name','Ticket'],axis=1)
test=pd.get_dummies(test)
encoded = list(test.columns)
print ("{} total features after one-hot encoding.".format(len(encoded)))
好了经过以上数据处理特征提取分类独热编码之后我们开始进行训练模型
这里我用了6个算法模型:
1.决策树,2.支持向量机 3.随机森林 4.AdaBoost 5.KNN 6.Xgboost
#首先引入需要的库和函数
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import make_scorer
from sklearn.metrics import accuracy_score,roc_auc_score
from time import time
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.neighbors import KNeighborsClassifier
from xgboost.sklearn import XGBClassifier
#列出需要使用的算法
alg1=DecisionTreeClassifier(random_state=29) ##决策树
alg2=SVC(probability=True,random_state=29) #支持向量机由于使用roc_auc_score作为评分标准,需将SVC中的probability参数设置为True
alg3=RandomForestClassifier(random_state=29) ##随机森林
alg4=AdaBoostClassifier(random_state=29) ##AdaBoost
alg5=KNeighborsClassifier(n_jobs=-1) ##KNN
alg6=XGBClassifier(random_state=29,n_jobs=-1)##Xgboost
然后调整参数范围
#列出调整的参数范围
parameters1={'max_depth':range(1,10),'min_samples_split':range(2,10)}
parameters2 = {"C":range(1,20), "gamma": [0.05,0.1,0.15,0.2,0.25]}
parameters3_1 = {'n_estimators':range(10,200,10)}
parameters3_2 = {'max_depth':range(1,10),'min_samples_split':range(2,10)} #搜索空间太大,分两次调整参数
parameters4 = {'n_estimators':range(10,200,10),'learning_rate':[i/10.0 for i in range(5,15)]}
parameters5 = {'n_neighbors':range(2,10),'leaf_size':range(10,80,20) }
parameters6_1 = {'n_estimators':range(10,200,10)}
parameters6_2 = {'max_depth':range(1,10),'min_child_weight':range(1,10)}
parameters6_3 = {'subsample':[i/10.0 for i in range(1,10)], 'colsample_bytree':[i/10.0 for i in range(1,10)]}#搜索空间太大,分三次调整参数
#定义通用函数框架
def fit_model(alg,parameters):
X=features
y=labels #由于数据较少,使用全部数据进行网格搜索
scorer=make_scorer(roc_auc_score) #使用roc_auc_score作为评分标准
grid = GridSearchCV(alg,parameters,scoring=scorer,cv=5) #使用网格搜索,出入参数
start=time() #计时
grid=grid.fit(X,y) #模型训练
end=time()
t=round(end-start,3)
print (grid.best_params_) #输出最佳参数
print ('searching time for {} is {} s'.format(alg.__class__.__name__,t)) #输出搜索时间
return grid #返回训练好的模型
训练出不同算法的模型
clf1=fit_model(alg1,parameters1)
clf2=fit_model(alg2,parameters2)
clf3_m1=fit_model(alg3,parameters3_1)
alg3=RandomForestClassifier(random_state=29,n_estimators=180)
clf3=fit_model(alg3,parameters3_2)
clf4=fit_model(alg4,parameters4)
clf5=fit_model(alg5,parameters5)
clf6_m1=fit_model(alg6,parameters6_1)
alg6=XGBClassifier(n_estimators=140,random_state=29,n_jobs=-1)
clf6_m2=fit_model(alg6,parameters6_2)
alg6=XGBClassifier(n_estimators=140,max_depth=4,min_child_weight=5,random_state=29,n_jobs=-1)
clf6=fit_model(alg6,parameters6_3)
把我们模型得出的预测结果保存为csv文件
def save(clf,i):
pred=clf.predict(test)
sub=pd.DataFrame({ 'PassengerId': Id, 'Survived': pred })
sub.to_csv("res{}.csv".format(i), index=False)
i=1
for clf in [clf1,clf2,clf3,clf4,clf5,clf6]:
save(clf,i)
i=i+1
欧克
然后我们简单看一下预测分
clf1.score(features,labels)
0.8005518054216222
clf2.score(features,labels)
0.8471177542055074
等等待,其他的就不放了
比较来说,svm和随机森林做出来的模型准确率相对来说稍微高一点点
看kaggle上面的准确率,最高可以模拟到80-85左右,在高太多就应该过拟合了.