当前位置:   article > 正文

机器学习实战(入门级) ------ Kaggle 泰坦尼克号幸存者预测 (随机森林,KNN,SVM)_kaggle泰坦尼克号乘客 存预测

kaggle泰坦尼克号乘客 存预测

前言

本篇将注重于机器学习预测模型的过程、数据分析以及项目实战落地。对于各种所使用的算法直接调用sklearn包,在这里不会说算法的原理和过程。有想看原理和过程的可以看我这两天整理的学习笔记。

关于kaggle:

就是一个面向机器学习和数据科学打比赛的地方,根据精度有排行榜,会有企业在里面,你要是解决了企业发布的项目,还会有奖金啥的。

我们没那么强,就利用他的数据集和项目来做练习吧。

先下载一下泰坦尼克号的数据集。

kaggle官网下载地址:https://www.kaggle.com/competitions/titanic/data

在这里插入图片描述

浏览kaggle网页不需要翻墙,不过要下载数据集或者提交代码需要登陆账号,登录账号要翻墙。

放一个迅雷的链接:点我下载

泰坦尼克号就不介绍了吧,大家应该都看过,没看过应该也听说过了。

本次小项目的目的就是预测哪些人可能在这次灾难中幸存下来。

这是一个分类问题,且是一个二分类问题,一个乘客的结果只有 幸存/未幸存 两种结果。

数据集介绍

下载完成之后就这三个文件:

在这里插入图片描述

gender_submision.csv:

  • Passenger: 乘客编号
  • Survived:是否幸存, 1幸存 0 未幸存

train.csv:

训练集数据

在这里插入图片描述

  • Passenger:乘客编号
  • Survived:相当于label 是否幸存,1 = 幸存 0 = 未幸存
  • Pclass:乘客所在船舱等级,跟一等座二等座商务座类似。
  • Name:乘客名,(话说乘客获救与否和名字有啥关系,可能只是想完善数据集?)
  • Sex:性别
  • Age:年龄
  • SibSp:兄弟姐妹的数量
  • Parh:父母子女的数量
  • Ticket:乘客购买的船票编号
  • Fare:船票价
  • Cabin:客舱号
  • Embarked:上船地点(S=英国南安普顿,C=法国瑟堡,Q=爱尔兰昆士敦)

test.csv

测试集,里面的字段和验证集一致,就是少了Survived是否幸存字段,毕竟测试集嘛,不能告诉你答案呀~~~

数据清洗

数据预处理

刚才在Excel中大致看了一下数据发现有很多的空缺值,数据值缺失会带来许多问题,所以必须要处理,来统计一下看看缺失的数据量级。

这块其实应该用jupyter写更好点,不过我刚才在写Bug,用Pycharm调试来着,所以就懒得换了,直接在Pycharm里继续干了,反正结果都一样哈哈。

titanic = pandas.read_csv('../data/Titanic数据集/train.csv')
s = titanic.info()
print(s)
  • 1
  • 2
  • 3

pandas.read_csv:
读取CSV文件内容

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

可以看到在训练集中,一共是891条数据,其中:

  • Age 缺失 177 条
  • Cabin 缺失 687 条
  • Embarked 缺失 2 条

这仅仅是train里的数据缺失,还没有算test里。小孩和老人有可能被优先营救,所以年龄是比较关键的数据,必须填充。

数据缺失的还是蛮多的,如果只少了一两条我一般都是直接删掉哈哈。

缺失值填充

数值填充用最简单的方法,取本字段的平均值进行填充。

titanic['Age'] = titanic['Age'].fillna(titanic['Age'].median())

  • 1
  • 2

fillna(titanic['Age'].median())
fillan() 函数主要用于填充,后面的参数就是用什么值填充,这里写的用‘Age’字段的均值填充。

填充之后看一下。

print(titanic.describe())
  • 1

describe()

该函数主要就是统计数据 有最大值 最小值 均值等等

输出:

       PassengerId    Survived      Pclass         Age       SibSp       Parch        Fare
count   891.000000  891.000000  891.000000  891.000000  891.000000  891.000000  891.000000
mean    446.000000    0.383838    2.308642   29.361582    0.523008    0.381594   32.204208
std     257.353842    0.486592    0.836071   13.019697    1.102743    0.806057   49.693429
min       1.000000    0.000000    1.000000    0.420000    0.000000    0.000000    0.000000
25%     223.500000    0.000000    2.000000   22.000000    0.000000    0.000000    7.910400
50%     446.000000    0.000000    3.000000   28.000000    0.000000    0.000000   14.454200
75%     668.500000    1.000000    3.000000   35.000000    1.000000    0.000000   31.000000
max     891.000000    1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

可以看到填充之后的Age字段一共891个 已经没有缺失值了。

这里使用的fillna()并非永久性填充。注释该语句后输出可以看到 ‘Age’字段变成了 714.000000 。

这里有个小技巧:

如果pycharm的输出有省略号导致看不到结果,可以添加下面几行代码让他显示完整:

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)
  • 1
  • 2
  • 3

顾名思义,增加输出个数的。

同样的来填充 ‘Embarked’ 字段值。

由于这是字符串,没办法求均值,也是使用最简单的方法,该字段中那个值最多,就用那个值填充缺失值。

统计一下 Embarked 字段每个值的个数总计,看看那个值最多。

print(titanic['Embarked'].value_counts())

输出:
S    644
C    168
Q     77
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用‘S’ 填充其中的缺失值:

titanic['Embarked'] = titanic['Embarked'].fillna('S')
  • 1

可以看一下填充前后变化:
这里可以用unique()函数看该字段的所有可能值,

print(titanic['Embarked'].unique())
titanic['Embarked'] = titanic['Embarked'].fillna('S')
print(titanic['Embarked'].unique())

输出:
['S' 'C' 'Q' nan]
['S' 'C' 'Q']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Cabin 字段缺失值非常多,这里先用‘U’ (unknow)进行填充

titanic['Cabin'] = titanic['Cabin'].fillna( 'U' )

  • 1
  • 2

数据优化

因为后面要做二分类,所以如果有‘str’的类型尽量变成‘int’或者‘float’类型。

这里面有个关键的字段就是性别,很有可能女性优先获救嘛,数据所给的是 ‘male’ 和 ‘female’,将他映射成 0和1来表示。

将 male变成0 female变成1:

titanic.loc[titanic['Sex'] == 'male','Sex' ] = 0
titanic.loc[titanic['Sex'] == 'female','Sex' ] = 1
  • 1
  • 2

loc()

该函数用于定位,接受两个参数,并以’,'分隔。第一个位置表示行,第二个位置表示列。

这里就是定位 ‘Sex’字段 当其等于 ‘male’ 时候改成等于0。

同样的,登船地点字段 Embarked 里面也是字符,将其改成数字, S = 0 , C = 1, Q = 2。

print(titanic['Embarked'].unique())   # ['S' 'C' 'Q' nan]
titanic.loc[titanic['Embarked'] == 'S','Embarked'] = 0
titanic.loc[titanic['Embarked'] == 'C','Embarked'] = 1
titanic.loc[titanic['Embarked'] == 'Q','Embarked'] = 2
  • 1
  • 2
  • 3
  • 4

将字符串数据映射成数值型数据的过程,这块有一个 独热编码(One-Hot Encoding)的概念简单提一下吧:

独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。
可以这样理解,对于每一个特征,如果它有m个可能值,那么经过独热编码后,就变成了m个二元特征(如成绩这个特征有好,中,差变成one-hot就是100, 010, 001)。并且,这些特征互斥,每次只有一个激活。因此,数据会变成稀疏的。

毕竟对于分类器来说,数值比字符串更好分类嘛。

训练过程

看一下刚才处理过后的数据的样子.在这里插入图片描述
一会使用Pclass、Sex 、 Age、 SibSp、 Parch 、 Fare 、Embarked 这七个特征进行训练。

使用支持向量机(SVM)、K均值、 K邻近(KNN)和 决策树-随机森林(RF)来算法实现本次模型训练。

先将用到的包全导进来

from sklearn.model_selection import KFold
from sklearn.metrics import confusion_matrix,accuracy_score
# SVM
from sklearn.svm import SVC
# KNN
from sklearn.neighbors import KNeighborsClassifier
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

SVM

直接定义出来SVM的计算模型:

alg = SVC(C=2,kernel='rbf',gamma=10,decision_function_shape='ovr')

  • 1
  • 2

没写错 就是SVC

SVM=Support Vector Machine 是支持向量
SVC=Support Vector Classification就是支持向量机用于分类
SVR=Support Vector Regression.就是支持向量机用于回归分析

这里面的参数解释一下:

  • C:错误术语的惩罚参数C。C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样对训练集测试时准确率很高,但泛化能力弱。C值小,对误分类的惩罚减小,允许容错,将他们当成噪声点,泛化能力较强。

  • kernel :核函数类型,

    • linear’:线性核函数
    • ‘poly’:多项式核函数
    • ‘rbf’:径像核函数/高斯核
    • ‘sigmod’:sigmod核函数
    • ‘precomputed’:核矩阵
  • gamma:核函数系数,float类型,可选参数,默认为auto。只对’rbf’ ,’poly’ ,’sigmod’有效。如果gamma为auto,代表其值为样本特征数的倒数,即1/n_features。

  • decision_function_shape : ‘ovo’,‘ovr’,默认=‘ovr’
    决策函数类型,可选参数’ovo’和’ovr’,默认为’ovr’。’ovo’表示one vs one,’ovr’表示one vs rest。

将我们用到的特征字段定义出来:

predictors = ['Pclass','Sex' ,'Age','SibSp', 'Parch' , 'Fare' ,'Embarked']
  • 1

然后采用K折交叉验证的方法。

kf = KFold(n_splits=3, shuffle=True, random_state=1)
  • 1

我之前在复现ZFnet论文的时候有详细的说过K折交叉验证,这里就简单的说一下,就是随机划分训练集为N份,分别取不同的一部分作为训练一部分作为测试,最后加权合并结果。

开始循环训练:

先放整体代码 后面再解释。

for train, test in kf.split(titanic[predictors]):  # 表示 划分这些个特征做交叉验证

    train_predictors = (titanic[predictors].iloc[train,:]) # 拿出来训练的数据 pandas.iloc方法提供了基于整数的索引方式
    train_target = titanic["Survived"].iloc[train] # 拿出来lable值
    # 模型计算
    alg.fit(train_predictors, train_target)
    test_predictions = (titanic[predictors].iloc[test,:]) # 拿出来测试的数据集

    test_target = titanic["Survived"].iloc[test] # 拿出来测试的lable值
    # 这里有个东西需要注意,训练集  测试集 验证集
    # predictions.extend(test_predictions) # 记录测试结果
    pre_train = alg.predict(train_predictors)
    pre_test = alg.predict(test_predictions)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

train_predictors = (titanic[predictors].iloc[train,:])
拿出来训练集的数据 。
pandas.iloc方法提供了基于整数的索引方式

train_target = titanic["Survived"].iloc[train]
拿出来训练集lable值

同样的方法 拿出来测试集的数据和测试集的lable值。

test_predictions = (titanic[predictors].iloc[test,:]) # 拿出来测试的数据集
test_target = titanic["Survived"].iloc[test] # 拿出来测试的lable值

这里有个东西我一开始蒙圈了,想了一下。

我这里说的测试集和训练集别忘了都是从一开始的train.csv里划分出来的。其实在一开始的test.csv文件应该叫做验证集。

alg.fit(train_predictors, train_target)
把计算模型定义出来,这里的参数就是训练集的数据和训练集的lable。

pre_train = alg.predict(train_predictors)
pre_test = alg.predict(test_predictions)
计算用SVM预测出来的值

最后我们可以打印看一下预测出来的值是什么样的:
accuracy_score() 计算正确率的函数,参数就是 原始数据标签和 使用模型预测出来的结果。

print('train',accuracy_score(train_target,pre_train))
print('test',accuracy_score(test_target,pre_test))

输出: # 一共三轮
train 0.9814814814814815
test 0.6127946127946128

train 0.9764309764309764
test 0.6363636363636364

train 0.9764309764309764
test 0.67003367003367
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

训练集的数据基本接近百分之百。这也没什么看的,主要是看测试集。
将每一次的测试结果放到一起来求一个平均值作为最后的结果。

完整代码

import pandas as pd

pd.set_option('display.max_columns', 1000)
pd.set_option('display.width', 1000)
pd.set_option('display.max_colwidth', 1000)

# 数据读取
titanic = pd.read_csv('../data/Titanic数据集/train.csv')
# 平均值填充年龄缺失值
titanic['Age'] = titanic['Age'].fillna(titanic['Age'].median())
# 年龄的字符串改int
titanic.loc[titanic['Sex'] == 'male','Sex' ] = 0
titanic.loc[titanic['Sex'] == 'female','Sex' ] = 1
# S填充Embarked缺失值
titanic['Embarked'] = titanic['Embarked'].fillna('S')
# Embarked 字符串改int
titanic.loc[titanic['Embarked'] == 'S','Embarked'] = 0
titanic.loc[titanic['Embarked'] == 'C','Embarked'] = 1
titanic.loc[titanic['Embarked'] == 'Q','Embarked'] = 2
# Cabin字段 用U填充
titanic['Cabin'] = titanic['Cabin'].fillna( 'U' )

print(titanic.head())

from sklearn.model_selection import KFold
from sklearn.metrics import confusion_matrix,accuracy_score
# SVM
from sklearn.svm import SVC

# KNN
from sklearn.neighbors import KNeighborsClassifier

alg = SVC(C=2,kernel='rbf',gamma=10,decision_function_shape='ovr')
predictors = ['Pclass','Sex' ,'Age','SibSp', 'Parch' , 'Fare' ,'Embarked']

kf = KFold(n_splits=3, shuffle=True, random_state=1)
# kf  K折交叉验证  这里是3折交叉验证

test_accurate = []
for train, test in kf.split(titanic[predictors]):  # 表示 划分这些个特征做交叉验证

    train_predictors = (titanic[predictors].iloc[train,:]) # 拿出来训练的数据 pandas.iloc方法提供了基于整数的索引方式
    train_target = titanic["Survived"].iloc[train] # 拿出来lable值
    # 模型计算
    alg.fit(train_predictors, train_target)

    test_predictions = (titanic[predictors].iloc[test,:]) # 拿出来测试的数据集
  
    test_target = titanic["Survived"].iloc[test] # 拿出来测试的lable值
    # 这里有个东西需要注意,训练集  测试集 验证集


    pre_train = alg.predict(train_predictors)
    pre_test = alg.predict(test_predictions)

    test_accurate.append(accuracy_score(test_target,pre_test))
test_accurate = sum(test_accurate)/3 # 取平均值
print(test_accurate)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

可以看到使用SVM模型的预测结果为:

0.6397306397306397 大概百分之63%左右。

KNN

上述代码不变,直接使用Sklearn提供的API。


alg = SVC(C=2,kernel='rbf',gamma=10,decision_function_shape='ovr')

改为
alg = KNeighborsClassifier(n_neighbors=10)

参数:
n_neighbors:取邻近点的个数k 。可以多试几个数 看看效果。

直接运行看最后结果:

0.7048260381593714 70%左右 比SVM高一点。

K-Means

在scikit-learn中,包括两个K-Means的算法,一个是传统的K-Means算法,对应的类是KMeans。
另一个是基于采样的Mini Batch K-Means算法,对应的类是MiniBatchKMeans。

from sklearn.cluster import KMeans
alg = KMeans(n_clusters=2, random_state=0)
  • 1
  • 2

关于KMeans的使用,可以直接看官方文档

  • n_clusters:数据集将被划分成 n_clusters个‘簇’即k值以及(int, optional, default: 8)。一般需要选取多个k值进行运算,并用评估标准判断所选k值的好坏,以获得较好的聚类效果。

RF

同样只更换一条语句就行了,不得不说sklearn真香!


alg = KNeighborsClassifier(n_neighbors=10)

改为
alg = RandomForestClassifier(random_state=1,n_estimators=10,min_samples_leaf=1,min_samples_split=2)

简单说一下参数:

  • random_state 随机种子
  • n_estimators 要构建的多少颗决策树
  • min_samples_split : 最小样本划分的数目,就是样本的数目少于等于这个值,就不能继续划分当前节点了
  • min_samples_leaf : 叶子节点最少样本数,如果某叶子节点数目小于这个值,就会和兄弟节点一起被剪枝。

结果也是非常的不错 0.7957351290684626 基本上在80%左右。

特征工程

数据和特征对于机器学习模型影响是巨大的,所以要查看一下现在用的这七个特征对于结果的影响,

直接放一个模板:

selector = SelectKBest(f_classif,k=5)
selector.fit(titanic[predictors],titanic['Survived'])
score = -np.log10(selector.pvalues_)
plt.bar(range(len(predictors)),score)
plt.xticks(range(len(predictors)),predictors,rotation='vertical')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这里面的各种参数可以查看官方文档

得到结果:
在这里插入图片描述
可以看到 年龄、孩子父母的个数、兄弟姐妹的个数、还有登船地点等的重要性较低。

小总结

  • 在KNN算法中 将参数n_neighbors 改成5 正确率为71%左右,稍高点。

  • 在RF随机森林中 将参数 n_estimators 改为500 得到0.811447 正确率大概81%左右,也高了一点,不过不能无脑增大,改到5000之后反而变成0.8了。而调参 min_samples_leaf=2,min_samples_split=4 之后 正确率能达到0.8282828282828283 大概 82%左右,又提高了一点。

  • 如果在前面K折交叉验证的时候使用的是老版本的 cross_validation,这个老版本不能用了,现在是model_selection。

  • 这个小项目中,其实还有一个重要的特征没有应用,就是名字,可以分析名字长度和名字里的代号作为特征继续训练,过程我没有写进去,但结果显示 名字是对结果有很大影响的一个特征。

  • 还有一个问题就是年龄居然没有对结果产生较大影响,这,,我觉得老人和小孩不应该优先获救嘛~~~

  • 之前在复现 GoogleNet的时候,作者为了ILSVRC 比赛,用到一个多模型融合,我觉得这里其实也可以将多模型一起用,查资料之后也发现有一个博主是这么做的,他将逻辑回归和随机森林进行融合,不过我看了一下他的代码,他融合的时候将这俩模型用列表存储,最后精度除以2。这里是不是有问题啊? 单个随机森林的精度很高,而逻辑回归的精度比较低,如果直接存列表里做模型融合,最后取平均值的话,岂不是会拉低总体的精度?还不如用单个的随机森林呀?这里没看懂,有明白的大佬,评论区指点我一下。

  • 还有一点就是,其实在这个数据集里并不适合使用K-Means算法,因为这是聚类算法嘛,聚类是无监督算法,而在这个泰坦尼克号的数据集里是已经给了lable的,所以可能这个算法并不合适,不过也可以用。

学习参考

数据值缺失处理:https://zhuanlan.zhihu.com/p/137175585

pandas输出值省略号问题:https://blog.csdn.net/XU_RAL_KO/article/details/109380846

pandas.loc()用法详解:http://c.biancheng.net/pandas/loc-iloc.html

pandas 统计列个数:https://waple.blog.csdn.net/article/details/80514073

独热编码:https://zhuanlan.zhihu.com/p/134495345

SVM 官方文档:https://scikit-learn.org.cn/view/83.html

sklearn K折交叉验证:https://blog.csdn.net/weixin_40283816/article/details/83242083

SVC\SVM\SVR:https://blog.csdn.net/ccc_bioinfo/article/details/108975556

sklearn.svm.SVC()函数:https://blog.csdn.net/TeFuirnever/article/details/99646257

decision_function_shape():https://blog.csdn.net/weixin_38100489/article/details/78363326

SVM的各种核函数:https://blog.csdn.net/batuwuhanpei/article/details/52354822
视频教程:https://www.bilibili.com/video/BV1WD4y1U7og?p=1

KNN KNeighborsClassifier 算法实现:http://c.biancheng.net/ml_alg/sklearn-knn.html

随机森林RandomForestClassifier :https://www.cnblogs.com/mdevelopment/p/9450909.html

特征影响程度的计算:https://blog.csdn.net/weixin_48266461/article/details/114108872

K-means:https://zhuanlan.zhihu.com/p/208306755

K-means 官方文档:https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/674668
推荐阅读
相关标签
  

闽ICP备14008679号