Kaggle入门——Titanic: Machine Learning from Disaster

Kaggle入门笔记——Titanic: Machine Learning from Disaster

  • 1 前言
  • 2 数据处理和分析过程:
    • 2.1 初识数据集
    • 2.2 填补缺失值:
    • 2.3 处理Sex、Name、Embarked、Ticket特征
    • 2.4 处理SibSp和Parch特征
    • 2.5 处理异常值
    • 2.6 特征选取
  • 3 模型构建与结果分析
  • 4 小结

1 前言

本人小萌新一枚,也是第一次写博客,想利用寒假时间通过实战学习数据挖掘、机器学习尤其是深度学习,偶然的机会了解到Kaggle平台,完成了第一个小的Project即“Titanic: Machine Learning from Disaster”,目前成绩是0.79425,排名前17%,通过博客记录做一个总结归纳。

2 数据处理和分析过程:

2.1 初识数据集

train.csv:用于训练模型的数据
test.csv:Kaggle平台用于检验结果正确性的数据
即提交的结果即为test.csv的类别标签(1表示survived,0表示unsurvived)
首先需要用到的模块:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from keras import models
from keras import layers
import keras.optimizers as optimizers

大概认识一下数据:

train = 'F:/kaggle/Titanic/Dataset/titanic/train.csv'
test = 'F:/kaggle/Titanic/Dataset/titanic/test.csv'
df1 = pd.read_csv(train,sep=',')
df2 = pd.read_csv(test,sep=',')
print(df1.info())

RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
None

各个特征的具体含义Kaggle上写的很详细,这里就不再赘述。

在建模前需要填补缺失值、处理异常值,同时Name、Sex、Ticket、Embarked列均为Object类型,需要转化为数值类型才便于分析

2.2 填补缺失值:

含有缺失值的特征有:Age、Cabin和Embarked
由于Cabin信息缺失过多,于是删除Cabin特征,保留Age和Embarked

  1. 对于Embarked特征:采用前一个非缺失值填充
df1['Embarked'].fillna(method='pad',axis=0,inplace=True)
  1. 对于Age特征:根据不同的Pclass(社会等级)进行均值填充(最开始并没有按照社会等级填充,经过测试发现效果不是很好)
age_1 = df1[df1['Pclass'] == 1]
age_1 = age_1['Age'].mean()
df1[df1['Pclass']==1].fillna(age_1,inplace=True)
age_2 = df1[df1['Pclass'] == 2]
age_2 = age_2['Age'].mean()
df1[df1['Pclass']==2].fillna(age_2,inplace=True)
age_3 = df1[df1['Pclass'] == 3]
age_3 = age_3['Age'].mean()
df1[df1['Pclass']==3].fillna(age_3,inplace=True)

2.3 处理Sex、Name、Embarked、Ticket特征

  1. 将Sex中male赋值为1,female赋值为0
df1['Sex'].replace('male',1,inplace = True)
df1['Sex'].replace('female',2,inplace = True)
  1. 对于Name特征:考虑名字长度和称呼与是否存活的关系进行赋值(有借鉴Kaggle讨论平台上的地方)

    将名字长度大于32的赋值为1,小于等于32的赋值为0

def fun(x):
    if x>32: #此处32为多次尝试后的经验值
        return 1
    else:
        return 0
        
Name_list = df1['Name'].apply(lambda x : fun(len(x)))
df1['Name'] = Name_list

名字称呼中绝大多数含有Mr、Mrs、Miss,根据此分别赋值为1、2、3,其余项赋值为0

bool1 = df1['Name'].str.contains('Mr\.')
bool2 = df1['Name'].str.contains('Mrs\.')
bool3 = df1['Name'].str.contains('Miss\.')
filter_Name1 = df1['Name']
filter_Name1[:] = 0
filter_Name1[bool1] = 1
filter_Name1[bool2] = 2
filter_Name1[bool3] = 3
df1['class'] = filter_Name1
  1. 对于Embarked特征:最开始采用直接赋值的方法,即’C’ = 1,‘Q’ = 2,‘S’ = 3
df1['Embarked'].replace('C',1,inplace=True)
df1['Embarked'].replace('Q',2,inplace=True)
df1['Embarked'].replace('S',3,inplace=True)

后将其变为Embarked_C、Embarked_Q、Embarked_S三个特征,并用0-1变量表示

df1['Embarked_C'] = df1['Embarked'].apply(lambda x: 1 if x==1 else 0)
df1['Embarked_Q'] = df1['Embarked'].apply(lambda x: 1 if x==2 else 0)
df1['Embarked_S'] = df1['Embarked'].apply(lambda x: 1 if x==3 else 0)
  1. 对于Ticket特征:EXCEL中采用“空格”分符分隔,然后读取最后一段数字作为Ticket特征(姑且认为是船票号码,可能与位置有关)

2.4 处理SibSp和Parch特征

考虑构建number特征表示乘客家人数量,即number = slisp+parch+1

df1['Number'] = df1['SibSp']+df1['Parch']+1

2.5 处理异常值

首先通过箱线图查看异常值

f,ax=plt.subplots(figsize=(10,8))
sns.boxplot(data=df1,ax=ax)
plt.show()

Kaggle入门——Titanic: Machine Learning from Disaster_第1张图片

乍一看貌似异常值不少,采用四分位法识别异常值(Fare和Age离群值较多,Number没处理)

def sifenfa(x):
    a = x.quantile(0.75)
    b = x.quantile(0.25)
    c = x
    d = x
    c[(c >= (a - b) * 1.5 + a) | (c <= b - (a - b) * 1.5)] = np.nan
    c.fillna(c.median(),inplace=True)
    d[(d >= (a - b) * 1.5 + a) | (d <= b - (a - b) * 1.5)] = np.nan
    d.fillna(d.median(), inplace=True)

sifenfa(df1['Fare'])
sifenfa(df1['Age'])

2.6 特征选取

internal_chars = df1.columns.astype(list)
corrmat = df1[internal_chars].corr()
plt.subplots(figsize=(10,10))
sns.heatmap(corrmat, square=True, linewidths=.5, annot=True)
plt.show()

Kaggle入门——Titanic: Machine Learning from Disaster_第2张图片
由于Embarked_Q特征与Survived标签相关性较弱,将其舍弃,采用剩余特征作为分类依据

3 模型构建与结果分析

由于前些时在学习keras框架,于是采用一个简单的全连接神经网络(DNN)作为分类模型

train_label = train_1['Survived']
train_data = train_1[['Name','Pclass','Sex','Fare','Age','Embarked_C','Embarked_S','Number','class','Ticket']]
test_label = test_1['Survived']
test_data = test_1[['Name','Pclass','Sex','Fare','Age','Embarked_C','Embarked_S','Number','class','Ticket']]

d_test = df2[['Name','Pclass','Sex','Fare','Age','Embarked_C','Embarked_S','Number','class','Ticket']]

#标准化后归一化
train_data = train_data.apply(lambda x : (x-np.mean(x))/np.std(x))
test_data = test_data.apply(lambda x : (x-np.mean(x))/np.std(x))
train_data = train_data.apply(lambda x : (x-np.min(x))/(np.max(x)-np.min(x)))
test_data = test_data.apply(lambda x : (x-np.min(x))/(np.max(x)-np.min(x)))

d_test = d_test.apply(lambda x : (x-np.min(x))/(np.max(x)-np.min(x)))
d_test = d_test.apply(lambda x : (x-np.min(x))/(np.max(x)-np.min(x)))


#DNN模型建立
shape1 = train_data.shape[1]
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(shape1,)))
model.add(layers.Dense(32, activation='relu'))
model.add(layers.Dropout(0.6))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dropout(0.8))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dropout(0.6))
model.add(layers.Dense(1, activation='sigmoid'))
#Dropout参数取0.5仍旧过拟合,选取0.6、0.8和0.6较为合适


model.compile(optimizer=optimizers.Adam(lr=0.0008),loss='binary_crossentropy',metrics=['acc'])
#参数batch_size = 16 、lr = 0.0008 经过多次尝试后较为合适
history = model.fit(train_data,train_label,epochs=200,batch_size=16,validation_data=(test_data, test_label))

plot_results(history)  #plot_results():keras书中用于可视化history的绘图方法
result = model.predict(d_test)
result1 = pd.DataFrame(result)
result1.to_excel('my_result.xlsx')

结果如下:经过调整模型参数、网络结构等可以让Training_loss和Validation_loss均降到0.4以下,同时验证精度可达到0.83以上(最高不到0.85)
Kaggle入门——Titanic: Machine Learning from Disaster_第3张图片
Kaggle入门——Titanic: Machine Learning from Disaster_第4张图片

4 小结

(1) DNN模型层数过深不好,而且貌似一般都需要加上Dropout防止过拟合。刚刚在Kaggle上看到一位大哥没做太多预处理,用一个简单的DNN就达到了0.80+的分数额,具体什么原因后面在学习过程中再出尝试。
(2) 特征工程非常重要。特征处理和选取上我最开始只是做了简单的筛选,分数就达到0.76(好吧虽然排名倒数),后来加上了Number和class特征,又增加了Ticket、Name的处理,才上升到0.79+,同时尝试过随机森林、支持向量机模型,但是效果没有DNN好(不过差距也不大)。总的来说给我感觉特征工程需要花很多工夫去做,如何处理得当,如何开发脑洞构思和联想挺考验人的。
(3) pandas_profiling,本次学习过程中了解到了pandas_profiling模块,一行代码认清原始数据集,在做项目过程中对问题分析和论文写作都很有帮助。

第一次写博客记录Project,算是一次小小的总结吧,为大四写毕业论文打个基础。不足之处太多太多,有待改进的地方数不胜数,希望可以在CSDN上学习的同时分享和总结自己的心得体会,取得更快更大的进步。

你可能感兴趣的:(Kaggle入门——Titanic: Machine Learning from Disaster)