Kaggle竞赛入门之特征选取(泰坦尼克号的灾难预测)

摘要 

        今天跟大家分享一个有关于我在kagge上面的第一次入门经验 希望能帮助到你更好的入门机器学习和人工智能。

        先跟大家介绍一下Kaggle这个平台,Kaggle是一个让人潜入机器学习比赛并通过比赛来学习的一个网站。其中包含大量的数据集以及大量的有实际应用价值的比赛。

Kaggle竞赛流程:

1.参加比赛:阅读比赛问题,接受比赛规则并访问比赛数据集。

2.准备工作:下载数据集在本地使用或者使用Kaggle上面免费的Jupyter Notebooks环境构建模型,并得到预测文件。

3.提交:将预测文件作为提交上传至Kaggle,Kaggle会根据上传的文件给予准确性的分数。 

4.查看排行榜:在排行榜上面可以看到你的得分处于一个怎么样的排名。

5.提高分数:查看论坛,访问其他对手的思路与见解。

题目描述:

泰坦尼克号是历史上最臭名昭著的沉船之一。1912年4月15日,被广泛认为不会沉没的RMS泰坦尼克号与冰山相撞后沉没。不幸的是,船上没有足够的救生艇供所有人使用,导致2224名乘客和船员中有1502人死亡。虽然生存有一些运气因素,但是有些人似乎比其他人更可能生存下来。在这个问题中,要求您建通过乘客数据(即姓名,年龄,性别,社会经济阶层等)立一个预测模型来回答以下问题:“什么样的人更可能生存”? 

在本次比赛中,您可以访问两个类似的数据集,其中包括乘客信息如姓名,年龄等。一个数据集的title为“train.csv”,另一个数据集的title为“test.csv”

需要提交一个仅包含PassengerId和Survived情况的csv文件。

问题解决了 我们先来对数据进行分析吧!

代码:

import numpy as np # 数组运算
import pandas as pd # 读取数据
import matplotlib.pyplot as plt #数据可视化
import seaborn as sns #数据可视化
import os
import warnings
import tensorflow as tf
warnings.filterwarnings("ignore")

for dirname,_,filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname,filename))

首先导入需要的库,包括数据分析中经常用到的Numpy,pandas以及matplotlib。warnings用来提示数据分析中的错误警告。下面的for循环是kaggle里面自带的,可以不用管。

# 读取csv文件数据
def read_data():
    train_data = pd.read_csv("/kaggle/input/titanic/train.csv")
    print("训练数据读取成功!")
    test_data = pd.read_csv("/kaggle/input/titanic/test.csv")
    print("测试数据读取成功!")
    return train_data,test_data
train_data, test_data = read_data()
train_data.head(3)

然后读取数据,并且显示pandas类型变量的前三行。运行结果是这样的:

下面一行代码将展示数据集的每一列的属性的详细信息

train_data.info()

运行结果如图:

 

 从这里我们可以发现如下几点信息

1、不是所有的数据都是891条,Age Cabin Embarked三类数据存在缺失的情况,需要根据需求进行调整

2、一些可能需要参与训练的数据的数据类型不是可计算的类型,需要根据需求进行转换

说明:

1、差额过大可以直接舍去,差额比较小可以进行填充,具体填充方法不一,一般按找序列的中位数进行填充

2、数据分类别的话一般用整数计算

# 查看具体的缺失值
# isnull 函数用于判断缺失值 返回一个布尔值 求和过后就能得到每一类数据的丢失数目
train_data.isnull().sum()

根据上面的结果我们可以看出 Cabin的缺失值数量过大 所以我们要对该数据进行删除,同时对缺损的Age和Embarked进行填充

# pands库里面的drop函数可以直接对某列进行删除 inplace=True的时候表示在原表进行操作
train_data.drop(columns = ['Cabin'], inplace = True)
train_data.drop(columns = ['Ticket'], inplace = True)
train_data.drop(columns = ['Name'], inplace=True)
train_data.drop(columns = ['PassengerId'], inplace=True)
# 测试集也应该保持一致
test_data.drop(columns = ['Cabin'], inplace=True)
test_data.drop(columns = ['Ticket'], inplace=True)
test_data.drop(columns = ['Name'], inplace=True)
test_data.drop(columns = ['PassengerId'], inplace=True)

Name和PassengerId与死亡情况显然没有直接关系 因此我们也选择删除。

#Embarked数据直接根据列表的最大值情况进行填充 测试集就不用填充了
train_data.Embarked = train_data.Embarked.fillna(train_data.Embarked.dropna().max())
#对于Sex 原始数据类型是object 为了便于参与模型计算 将Sex改为整数类型
train_data['Sex'] = train_data['Sex'].map({"female":1,"male":0}).astype(int)
test_data['Sex'] = test_data['Sex'].map({"female":1,"male":0}).astype(int)
# 对于Age缺失值的补充 为了让数据之间的联系关系更加密切
# 通过观察数据,性别和购票等级的年龄分布存在一定的差异,于是根据性别和购票等级进行填充
guess_train_ages = np.zeros((2,3))
guess_test_ages = np.zeros((2,3))
# .dropna()表示除去存在缺损值的行 median()表示取中位数
for i in range(0,2):
    for j in range(0,3):
        remain_train_age = train_data[(train_data['Sex'] == i)&(train_data['Pclass'] == j+1)]['Age'].dropna()
        age_train_guess = remain_train_age.median()
        guess_train_ages[i,j] = int(age_train_guess/0.5+0.5) * 0.5
        
        remain_test_age = test_data[(test_data['Sex'] == i)&(test_data['Pclass'] == j+1)]['Age'].dropna()
        age_test_guess = remain_test_age.median()
        guess_test_ages[i,j] = int(age_test_guess/0.5+0.5)*0.5
# 在机器学习中对数据进行处理时 采用四舍五入的方式会导致真实数据往更大的一方偏移
# 于是一般都采用四六入五取偶 这样会在一定程度上降低数据的误差

for i in range(0,2):
    for j in range(0,3):
        train_data.loc[(train_data.Age.isnull()) & (train_data.Sex == i) & \
                       (train_data.Pclass == j+1),'Age'] = guess_train_ages[i,j]
        test_data.loc[(test_data.Age.isnull())&(train_data.Sex == i )& \
                     (test_data.Pclass == j+1),'Age'] = guess_test_ages[i,j]
train_data['Age'] = train_data['Age'].astype(int)
test_data['Age'] = test_data['Age'].astype(int)
test_data.loc[test_data.Fare.isnull(),'Fare']=test_data['Fare'].dropna().median()

Age与Embarked数据填充方式如上。具体就是按照没有缺损的表格根据性别和票价的之间的联系来填充Age并且取中位数。Embarked数据就直接取一个无缺损的最大值就行。

填充完成过后在运行一下下面这段代码:

train_data.isnull().sum()

 

发现缺损值已经填充完毕。

接下来我们查看一下数据之间的关系,查看之前先了解一下有关于相关性系数的知识,这里介绍一下皮尔森相关性系数:

 大致就是:检查两个变量之间变化趋势的方向以及程度,值范围-1到+1,0表示两个变量不相关,正值表示正相关,负值表示负相关,值越大相关性越强。
计算积距pearson相关系数,连续性变量才可采用;计算Spearman秩相关系数,适合于定序变量或不满足正态分布假设的等间隔数据; 计算Kendall秩相关系数,适合于定序变量或不满足正态分布假设的等间隔数据。

了解过后我们直接引pandas里面的库查看属性与存亡之间的相关性:

train_data.corr()["Survived"].sort_values(ascending=False)

 

可以看出Sex和Fare对结果有明显的相关性
PassengerId对结果的相关性微乎其微
Pclass对结果有强烈的负相关

需要知道一个机器学习里面的知识:如果属性之间存在交互,而且只有其中少部分属性与结果的相关性更强,那么这样的提取效果并不会很好。下图展示所有属性之间的相关性:

sns.set(rc = {'figure.figsize':(10,6)})
sns.heatmap(train_data.corr(), annot = True, fmt='.2g', cmap='YlGnBu')

 上图可以观察到 Parch和Sibsp之间有很强的相关性,但是同结果的相关性并不高,于是考虑将二者合并 并且限定数据范围在true和false之间(即有无家人陪伴),同时将一些数据的类型转换到可计算的数据类型,由于数据之间差距不会很大,这里直接将所有数据都规范到整数。

#上图可以观察到 Parch和Sibsp之间有很强的相关性,但是同结果的相关性并不高
#于是考虑将二者合并 并且限定数据范围在true和false之间(即有无家人陪伴)\
train_data['Family_Size'] = train_data["Parch"] + train_data["SibSp"]+1
train_data['Alone'] = 0 #设所有人都有家人陪伴 记为0
train_data.loc[train_data['Family_Size'] == 1,'Alone'] = 1 #当家人为1时便是无家人,记为1

test_data['Family_Size'] = test_data["Parch"] + test_data["SibSp"]+1
test_data['Alone'] = 0
test_data.loc[test_data['Family_Size'] == 1,'Alone'] = 1

#类似于姓名 年龄 费用这样的数据参差不齐且有的数据类型不可进行计算
#可以把这些数据手动归为某个类别进行编码

#对年龄分类编码 类别可以自定义 本文将Age分为五个类别
train_data.loc[train_data['Age']<=16,'Age']=0
train_data.loc[(train_data['Age']>16)& (train_data['Age']<=32),'Age'] = 1
train_data.loc[(train_data['Age']>32)& (train_data['Age']<=48),'Age'] = 2
train_data.loc[(train_data['Age']>48)& (train_data['Age']<=64),'Age'] = 3
train_data.loc[train_data['Age']>64,'Age'] = 4

test_data.loc[test_data['Age']<=16,'Age']=0
test_data.loc[(test_data['Age']>16)& (test_data['Age']<=32),'Age'] = 1
test_data.loc[(test_data['Age']>32)& (test_data['Age']<=48),'Age'] = 2
test_data.loc[(test_data['Age']>48)& (test_data['Age']<=64),'Age'] = 3
test_data.loc[test_data['Age']>64,'Age'] = 4

#对费用分类编码 
train_data.loc[train_data['Fare']<=130,'Fare'] = 0
train_data.loc[(train_data['Fare']>130) & (train_data['Fare']<=256),'Fare'] = 1
train_data.loc[(train_data['Fare']>256) & (train_data['Fare']<=384),'Fare'] = 2
train_data.loc[train_data['Fare']>130,'Fare'] = 3
train_data['Fare'] = train_data['Fare'].astype(int)

test_data.loc[test_data['Fare']<=130,'Fare'] = 0
test_data.loc[(test_data['Fare']>130) & (test_data['Fare']<=256),'Fare'] = 1
test_data.loc[(test_data['Fare']>256) & (test_data['Fare']<=384),'Fare'] = 2
test_data.loc[test_data['Fare']>130,'Fare'] = 3
test_data['Fare'] = test_data['Fare'].astype(int)

#对Embarked分类编码
train_data['Embarked'] = train_data['Embarked'].map({'S':0,'C':1,'Q':2}).astype(int)               
test_data['Embarked'] = test_data['Embarked'].map({'S':0,'C':1,'Q':2}).astype(int)
#说明: 为什么Age不用astype 其余用了astype进行数据类型转换?
#赋值的过程中 将浮点数或者整数最后赋值成一个整数时 数据类型会和原来保持一致或者默认为浮点数
#像这里的Age原来就是整数类型 所以不需要改变数据类型 但是Fare和Embarked原来不是整数类型
#所以需要再转换成整数类型

数据类型改变过后,我们再来看一下数据内容吧

train_data.head()

 

所有的数据都规划到了可参与计算的整数。

最后我们直接来进行特征提取吧

#接下来可以开始使用sklearn直接建立特征提取模型了
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
# 通过之前的分析我们指导只需要8个属性 直接提取出来
fs = SelectKBest(score_func=f_classif, k=8)

print(train_data.shape)
Selected_train_data = fs.fit_transform(train_data.iloc[:,1:], train_data["Survived"])
print(Selected_train_data.shape)
train_label = np.array(train_data["Survived"])

 

可以看到数据有原来的10提取到了现在的8,说明略过一些相关性差的属性。最后我们就可以使用这8个属性进行传统的机器学习方法或者是神经网络模型去进行预测了。

我这里就使用很简单的几个Tensorflow的全连接层进行预测吧

# 创建神经网络模型进行训练
model = tf.keras.Sequential([
    tf.keras.layers.Dense(32,input_shape=(8,),activation='relu'),
    tf.keras.layers.Dense(64,activation='relu'),
    tf.keras.layers.Dense(128,activation='relu'),
    tf.keras.layers.Dense(64,activation='relu'),
    tf.keras.layers.Dense(32,activation='relu'),
    tf.keras.layers.Dense(1,activation='sigmoid')
])
model.compile(
    optimizer = 'adam',
    loss = tf.keras.losses.binary_crossentropy,
    metrics = ['acc']
)
model.fit(X_train,Y_train,epochs=200,validation_data=(X_test,Y_test))

 

 可以看到准确率从最开始的63涨到了87测试集到了85,当然还有更好的方法去优化这个模型。

本文仅仅是给初学者提供一种数据处理和特征提取的方法。如果有更好的方法,欢迎在评论区留言!谢谢

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值