首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Kaggle_Titanic逻辑回归生存预测

本文详述了Kaggle的Titanic幸存者预测这一分类问题,包括数据的探索性分析和可视化、数据预处理、特征工程、建模以及超参数的调优等。

一、初探数据

先观察训练集的前几行数据,如下:

#导入第三方库

importwarnings

warnings.filterwarnings('ignore')

importmatplotlib.pyplotasplt

importseabornassns

importpandasaspd

importnumpyasnp

importstatsmodels.formula.apiassmf

fromsklearn.ensembleimportRandomForestRegressor

fromstatsmodels.stats.outliers_influenceimportvariance_inflation_factor

fromsklearn.model_selectionimporttrain_test_split

fromsklearn.metricsimportroc_auc_score

#读取数据

data_train=pd.read_csv('E:/train.csv')

print(data_train)

每个特征的具体含义如下:

PassengerId => 乘客ID

Pclass => 乘客等级(1/2/3等舱位)

Name => 乘客姓名

Sex => 性别

Age => 年龄

SibSp => 堂兄弟/妹个数

Parch => 父母与小孩个数

Ticket => 船票信息

Fare => 票价

Cabin => 客舱

Embarked => 登船港口

#信息的总览

print(data_train.info())

从信息的总览可以看出,训练集中总共有891名乘客,Age(年龄)、Cabin(客舱)、Embarked(登船港口)等这几个特征存在缺失。

二、数据的探索性分析

每个乘客拥有那么多特征,那我们如何知道哪些特征更有用呢?这点就必须对数据有足够的认识,看看每个特征和最后的Survived之间有什么样关系呢?

2.0、目标变量Survived的分布

首先你得清楚目标变量Survived的分布,是否出现正负样本分布不均匀的情况,当其分布不均匀时,如何平衡,这些都必须考虑的问题。

# Survived的分布

data_train['Survived'].value_counts().plot.pie(autopct='%1.2f%%')

plt.show()

可见正负样本分布还算均匀,不需要平衡。

2.1、性别与是否存活的关系

sns.factorplot('Sex','Survived',data=data_train,size=3,aspect=1.5)

plt.title('Sex and Survived rate')

plt.show()

从上图可视化结果来看,女性的存活率远高于男性;性别无疑也要作为重要特征加入最后的模型之中。

2.2、乘客社会等级与是否存活的关系

sns.factorplot('Pclass','Survived',data=data_train,size=3,aspect=1.5)

plt.title('Pclass and Survived rate')

plt.show()

不同社会等级可能和财富/地位有关系,最后获救的概率可能会不一样;社会等级越高,存活率就越高。

2.3、配偶及兄弟姐妹的数量与是否存活的关系

sns.factorplot('SibSp','Survived',data=data_train,size=3,aspect=1.5)

plt.title('SibSp and Survived rate')

plt.show()

配偶及兄弟姐妹适中的乘客存活率越高。

2.4、父母与子女的数量与是否存活的关系

sns.factorplot('Parch','Survived',data=data_train,size=3,aspect=1.5)

plt.title('Parch and Survived rate')

plt.show()

父母与子女数量适中的,存活率更高。

2.5、年龄与是否存活的关系

facet=sns.FacetGrid(data_train,palette='Greens_d',hue='Survived',aspect=2)

#使用map函数映射kde,以Age作为X轴

facet.map(sns.kdeplot,'Age',shade=True)

#设置x轴的取值范围为到最大值

facet.set(xlim=(,data_train['Age'].max()))

facet.add_legend()

plt.show()

年龄对获救概率也有一定的影响,可以看出未成年人的存活率高于成年人。

2.6、船票费与是否存活的关系

facet=sns.FacetGrid(data_train,palette='Greens_d',hue='Survived',aspect=2)

#使用map函数映射kde,以Fare作为X轴

facet.map(sns.kdeplot,'Fare',shade=True)

#设置x轴的取值范围为到200

facet.set(xlim=(,200))

facet.add_legend()

plt.show()

可以看出船票费越高,存活率就越高。

2.7、登船港口与是否存活的关系

sns.factorplot('Embarked','Survived',data=data_train,size=3,aspect=2)

plt.title('Embarked and Survived rate')

plt.show()

可以看出在不同港口上船,存活率不同,C港口最高,Q次之,S最低。

三、数据预处理

数据的预处理指的是缺失值和异常值的处理,暂时只针对缺失值进行处理,通常的缺失值处理方式有如下几种。

如果缺值的样本比例极高,我们可能就直接删除了,作为特征加入的话,可能反倒带入noise,影响最后的结果。

如果缺失的样本适中,而该特征属于分类变量,可以把NaN作为一个新类别,加到类别特征中;或者通过中位数、众数、平均数等进行填充。

缺失的值个数并不是特别多,而该特征属于连续型变量,那我们也可以试着根据已有的值,通过模型预测,来填充缺失值。

目前的缺失特征有Age(年龄)、Cabin(客舱)、Embarked(登船港口);处理方式如下:

3.1、针对Cabin(客舱)的缺失,我们的处理方式是把NaN作为一个新类别,加到类别特征中。

3.2、针对Embarked(登船港口)的缺失,缺失比例较小,采用众数的方式进行填充。

3.3、针对Age(年龄)的缺失,我们采用的是scikit-learn中的RandomForest来预测缺失的年龄数据。

#统计缺失值比例

missing_rate=data_train.isnull().sum()/len(data_train)

# print(missing_rate)

# Cabin处理

data_train['Cabin']=data_train['Cabin'].apply(lambdax:ifxisnp.nanelse1)

# Embarked处理

data_train['Embarked']=data_train['Embarked'].fillna(data_train['Embarked'].mode()[])

# Age处理

defmissing_ages(df):

age_df=df[['Age','Fare','Parch','SibSp','Pclass']]

known_age=age_df[age_df.Age.notnull()]

unknown_age=age_df[age_df.Age.isnull()]

y=known_age.iloc[:,]

X=known_age.iloc[:,1:]

# fit到RandomForestRegressor之中

rfr=RandomForestRegressor(random_state=,n_estimators=500,n_jobs=-1)

rfr.fit(X,y)

#用得到的模型进行未知年龄结果预测

predictedAges=rfr.predict(unknown_age.iloc[:,1:])

#用得到的预测结果填补原缺失数据

df.loc[ (df.Age.isnull()),'Age']=predictedAges

returndf

data_train=missing_ages(data_train)

四、特征工程

有这么一句话在业界广泛流传:数据和特征决定了机器学习的上限,而模型和算法只是无限逼近这个上限而已。那么特征工程到底是什么呢?其本质是特征衍生和尺度变换,目的是最大限度的从原始特征中提取、衍生特征。下面将以示例的形式展开分析:

4.1、Sex和Age特征的提取

还记得副船长说『小孩和女士先走』,就这么一句话涵盖了多少信息,基于以上探索性分析,将年龄为16岁作为一个分界点,对其进行分类,小于16岁为‘child’,大于16岁保留性别。

# Sex和Age组合特征

defget_person(passenger):

age,sex=passenger

return'child'ifage

data_train['Person']=data_train[['Age','Sex']].apply(get_person,axis=1)

#删除Sex变量

data_train.drop(['Sex'],axis=1,inplace=True)

4.2、Parch和SibSp特征的提取

将Parch和SibSp特征组合为一个Famliy变量,示例如下:

# Parch和SibSp组合特征

data_train['Family']=data_train['Parch']+data_train['SibSp']

data_train['Family']=data_train['Family'].apply(lambdax:ifx==else1)

#删除Parch和SibSp

data_train.drop(['Parch','SibSp'],axis=1,inplace=True)

4.3、Fare特征的提取

基于数据的探索性分析,可以看出船票费大于20时,乘客的存活率普遍比20以下要高,故以20作为切分点。

# Fare特征的提取

data_train['Fare']=data_train['Fare'].apply(lambdax:ifx

4.4、Person、Pclass、Cabin、Embarked和Family特征的提取

针对这五个特征的处理方式,都是转换为哑变量。

# Person/Pclass/Cabin/Embarked/Family哑编码处理

col=['Person','Pclass','Cabin','Embarked','Family']

defdummy(df,col):

foriincol:

data_dummy=pd.get_dummies(df[i],prefix=i)

df=df.join(data_dummy)

df.drop(i,axis=1,inplace=True)

returndf

data_titanic=dummy(data_train,col)

#删除无关原始特征

data_titanic.drop(['Name','Ticket'],axis=1,inplace=True)

print(data_titanic)

4.5、尺度的变换

目前只针对年龄这个特征进行尺度的标准化处理。

#对Age进行标准化处理

defz_score(x):

return(x-x.mean())/x.std()

data_titanic['Age']=data_titanic['Age'].transform(z_score)

五、模型的构建

本文主要介绍基于逻辑回归的分类预测,该逻辑回归位于statsmodels模块中,下面将以示例具体介绍。

5.1、逻辑回归对共线性较为敏感,第一步首先是判断共线性问题,可以利用VIF检验,一般认为大于10的变量就存在共线性。

#多重共线性检验

Y=data_titanic['Survived']

X=data_titanic.drop(['PassengerId','Survived'],axis=1)

feature_selection=list(X.columns)

foriinrange(len(feature_selection)):

print('{}:{}'.format(feature_selection[i],variance_inflation_factor(X.values,i)))

一般筛选的规则是从下往上逐个剔除,直到所有特征的VIF值都小于10为止。最后结果如下所示:

#删除共线特征

X.drop(['Family_1','Embarked_S','Cabin_1','Pclass_3','Person_male'],axis=1,inplace=True)#

feature_selection=list(X.columns)

foriinrange(len(feature_selection)):

print('{}:{}'.format(feature_selection[i],variance_inflation_factor(X.values,i)))

5.2、逻辑回归通常对特征的显著性也同样敏感,第二步就需要进行特征的显著性检验;根据概率P值逐个剔除,直到所有的P值都小于0.1或者0.05。如下所示是我经过删除不显著变量之后的结果:

#删除不显著的变量

X.drop(['Embarked_Q','Family_0','Pclass_1','Fare'],axis=1,inplace=True)

#需要自行添加逻辑回归所需的intercept变量

X['intercept']=1.0

#划分训练集和测试集

X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.3,random_state=1)

#构建逻辑回归分类器

lr=smf.Logit(y_train,X_train).fit()

print(lr.summary())

5.3、训练模型以及模型的评估

介于比赛官方的要求,模型的评估采用的是AUC值作为此次比赛的评估标准,示例如下:

#训练误差

predicted=lr.predict(X_train)

print('AUC Score (Train): {:.5f}'.format(roc_auc_score(y_train,predicted)))

#测试误差

y_pred=lr.predict(X_test)

print('AUC Score (Test): {:.5f}'.format(roc_auc_score(y_test,y_pred)))

AUC Score (Train):0.87649

AUC Score (Test):0.80699

此次的分享到这差不多结束了,整个建模的流程大体就这么多,暂时没有涉及超参数的调节以及模型的融合,后期的文章会继续补充,感谢亲们的支持和关注。

学习与分享,关注小号

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180331G1HS1800?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券