python学到哪知道baseline_【Kaggle泰坦尼克号】用决策树快速的撸一个Baseline

本文介绍了如何使用决策树模型快速建立一个泰坦尼克号生存预测的Baseline。首先,阐述了选择决策树作为模型的原因,并对泰坦尼克号数据集进行了初步分析,包括特征介绍和缺失值处理。接着,通过数据预处理,如特征选择、缺失值填充和数据转换,使数据满足模型要求。然后,利用sklearn库构建并训练决策树模型,通过学习曲线和网格搜索调整参数,最终提高了模型在测试集上的准确度。文章总结了完成Kaggle入门挑战的意义,并提出特征工程的重要性以及后续优化方向。
摘要由CSDN通过智能技术生成

1. 引言

检验学习成果最快的方式就是去实战,kaggle上提供了各式各样练手和比赛的数据集,"Titanic: Machine Learning from Disaster"就是最经典的入门比赛,既适合经验丰富的Data scientist去深入分析争取top3%的成绩,也适合新手应用数据集对所学习的分类算法来练手。

应用机器学习,千万不要一上来就试图做到完美,先撸一个baseline的model出来,再进行后续的分析步骤,一步步提高。—— Andrew Ng

本篇就是基于决策树模型快速的撸一个baseline model。

选择决策树的原因:模型对数据的要求不高,一般原始数据简单的预处理就能让模型跑起来(如果要得到更高的分数,数据预处理特征工程还是不能少)

2. 泰坦尼克号背景介绍

泰坦尼克号的沉没是历史上最臭名昭著的沉船之一,泰坦尼克号在首航中撞上冰山沉没,2224名乘客和船员中1502人遇难。这一耸人听闻的悲剧震惊了国际社会,并导致了对船舶更严格的安全规定。

我们的任务是运用机器学习的工具,分析船上人员的信息来预测什么样的人能够从船难中活下来。

3. 数据集分析

3.1 特征介绍

Variable

Definition

Keysurvival

是否生存

0 = No, 1 = Yes

pclass

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

1 = 1st, 2 = 2nd, 3 = 3rd

sex

性别

Age

年龄

sibsp

堂兄弟/妹个数

parch

父母与小孩个数

ticket

船票信息

fare

票价

cabin

客舱

embarked

登船港口

C = Cherbourg, Q = Queenstown, S = Southampton

3.2 查看缺失值和特征类型

In [1]:

#导入数据

import pandas as pd

data = pd.read_csv('Taitanic data/data.csv')

data.info()

out [1]:

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

通过data.info()和data.head(),我们可以观察出有多少乘客、特征的数据类型和缺失值。

In [2]:

#观察前5行数据

data.head()

out [2]:

PassengerId

Survived

Pclass

Name

Sex

Age

SibSp

Parch

Ticket

Fare

Cabin

Embarked0

1

0

3

Braund, Mr. Owen Harris

male

22.0

1

0

A/5 21171

7.2500

NaN

S

1

2

1

1

Cumings, Mrs. John Bradley (Florence Briggs Th...

female

38.0

1

0

PC 17599

71.2833

C85

C

2

3

1

3

Heikkinen, Miss. Laina

female

26.0

0

0

STON/O2. 3101282

7.9250

NaN

S

3

4

1

1

Futrelle, Mrs. Jacques Heath (Lily May Peel)

female

35.0

1

0

113803

53.1000

C123

S

4

5

0

3

Allen, Mr. William Henry

male

35.0

0

0

373450

8.0500

NaN

S

决策树模型的输入要求就是特征必须为数值型的数据,且sklearn无法自动的处理缺失值,因此为了尽快的撸出baseline,我们就不过多的进行分析,先把数据调整成符合模型要求的样子。

4. 数据预处理

4.1 特征选择

一个正确的数学模型应当在形式上是简单的 —— 吴军,《数学之美》

特征选择的目的是为了去掉不含信息量或是信息量较少的特征,特征选择和方法很多,如果特征上百个可以选择降维、相关系数分析、卡方检验等方法,既然是暴力的撸出一个baseline,就直接肉眼观察剔除不重要的特征。

PassengerId?Name? 剔除

Ticket 观察一下每张船票都不一样,就跟条形码一样是无用特征

Cabin 缺失值严重,剔除

In [3]:

#特征选择

data.drop(['Cabin','Name','Ticket','PassengerId']

,inplace=True

,axis=1

)

4.2 缺失值处理

由于模型本身没有处理缺失值的能力,我们需要人工的处理缺失值。

缺失值处理的方法常见的有均值填充、中位数填充、归为一类新的特征甚至可以用随机森林或者K-means来预测,还是那句话,先撸出一个model来,怎么快怎么来!

Age大部分数据还是完整的(714/891),因此直接上均值填充填充

In [4]:

#处理缺失值

data['Age'] = data['Age'].fillna(data['Age'].mean())

In [5]:

data.info()

Out [5]:

RangeIndex: 891 entries, 0 to 890

Data columns (total 8 columns):

Survived 891 non-null int64

Pclass 891 non-null int64

Sex 891 non-null object

Age 891 non-null float64

SibSp 891 non-null int64

Parch 891 non-null int64

Fare 891 non-null float64

Embarked 889 non-null object

dtypes: float64(2), int64(4), object(2)

memory usage: 55.8+ KB

Embarked 的缺失记录只有2条,怎么快怎么来——直接把那两条记录删掉!

In [6]:

#删除含有空值的记录

data = data.dropna(axis=0)

In [7]:

data.info()#再次观察数据

Out [7]:

Int64Index: 889 entries, 0 to 890

Data columns (total 8 columns):

Survived 889 non-null int64

Pclass 889 non-null int64

Sex 889 non-null object

Age 889 non-null float64

SibSp 889 non-null int64

Parch 889 non-null int64

Fare 889 non-null float64

Embarked 889 non-null object

dtypes: float64(2), int64(4), object(2)

memory usage: 62.5+ KB

非常干净了,缺失值的处理到此为止!

4.3 数据转换

数据转换的目的就是把人看的数据转换成计算机看得懂的数据。

sklearn的模型无法识别male和female,我们需要用0/1来代替

In [8]:

#男性为1(True),女性为0(False)

data['Sex'] = (data['Sex'] == 'male').astype('int')

再看看Embarked,官方数据集高速我们总共有三个港口分别是C、Q、S

同样的方式处理,映射成0,1,2

In [9]:

data['Embarked'] = data['Embarked'].map({'S':0,'C':1,'Q':2})

再看看现在数据是什么样子

In [10]:

data.head()

Survived

Pclass

Sex

Age

SibSp

Parch

Fare

Embarked0

0

3

1

22.0

1

0

7.2500

0

1

1

1

0

38.0

1

0

71.2833

1

2

1

3

0

26.0

0

0

7.9250

0

3

1

1

0

35.0

1

0

53.1000

0

4

0

3

1

35.0

0

0

8.0500

0

到这里一个简单的数据预处理就结束了,没有过多的数据分析,仅仅是把数据处理成模型能够处理的格式。

5. 决策树分类

到了这里就是真正的运用机器学习算法了。

第一步,把数据调整成sklearn能够传入的格式:

sklearn的模型都是把特征和标签分别传入训练,否则一整个数据集模型也无法得知哪个才是特征哪个是标签

In [11]:

X = data.iloc[:,data.columns != "Survived"]

y = data.iloc[:,data.columns == "Survived"]

第二步,划分训练集和测试集:

我们把训练集和测试集按7:3 进行划分

In [12]:

from sklearn.tree import DecisionTreeClassifier

from sklearn.model_selection import train_test_split

from sklearn.model_selection import cross_val_score

Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3)

#test_size是测试集占总数据集的比例

第三步,导入模型,粗略跑一下查看结果:

sklearn的模型运用基本上分为三步:调用模型、训练模型、评价模型。三行代码如下。

In [13]:

#1.声明分类树模型

clf = DecisionTreeClassifier()

#2.传入训练集训练模型

clf = clf.fit(Xtrain, Ytrain)

#3.传入测试集评价模型

score_ = clf.score(Xtest, Ytest)

score = cross_val_score(clf,X,y,cv=10).mean() #交叉验证集准确度

print('测试集准确度:{}\n交叉验证集准确度:{}'.format(score_,score))

Out [13]:

测试集准确度:0.7715355805243446

交叉验证集准确度:0.7717058222676201

以上,一个非常粗略的baseline就撸出来了。

6. 模型参数调整

上面那个粗略的分类树模型都是用默认参数,简单方便但是效果确不是很好,至少调整一个合适的参数还是能够继续提高准确度。

6.1 DecisionTreeClassifier参数介绍

调参,我们首先要知道有哪些参数以及参数的含义。这里就先列出分类树常用的参数

参数=默认

介绍criterion=‘gini’

gini/entropy 划分节点的指标

splitter=‘best’

节点分支策略

max_depth=‘None’

树最大深度

min_samples_split=2

一个中间节点分支需要的最少样本(

min_samples_leaf=1

分支后叶节点至少需要的最少样本

random_state

随机数种子

可以通过试不同的变量来确定一部分参数

6.2 学习曲线调整参数

In [14]:

#分别记录不同参数在测试集和训练集下准确度

import matplotlib.pyplot as plt

tr_entropy = []

te_entropy = []

tr_gini = []

te_gini = []

#尝试深度从1~10

for i in range(10):

clf = DecisionTreeClassifier(random_state=25

,max_depth=i+1

,criterion='entropy' #尝试信息增益

)

clf.fit(Xtrain,Ytrain)

score_tr = clf.score(Xtrain,Ytrain)

score_te = cross_val_score(clf,X,y,cv=10).mean()

tr_entropy.append(score_tr)

te_entropy.append(score_te)

clf = DecisionTreeClassifier(random_state=25

,max_depth=i+1

,criterion='gini' #尝试基尼系数

)

clf.fit(Xtrain,Ytrain)

score_tr = clf.score(Xtrain,Ytrain)

score_te = cross_val_score(clf,X,y,cv=10).mean()

tr_gini.append(score_tr)

te_gini.append(score_te)

fig, (ax0, ax1) = plt.subplots(1,2, figsize=(18, 6))

ax0.plot(range(1,11),tr_entropy,color='r',label='train')

ax0.plot(range(1,11),te_entropy,color='blue',label='test')

ax0.set_xticks(range(1,11))

ax0.set_title('entropy')

ax0.legend()

ax1.plot(range(1,11),tr_gini,color='r',label='train')

ax1.plot(range(1,11),te_gini,color='blue',label='test')

ax1.set_xticks(range(1,11))

ax0.set_title('gini')

ax1.legend()

print('entropy上的最好准确度为{}\njini上的最好准确度为{}'.format(max(te_entropy),max(te_gini)))

Out [14]:

entropy上的最好准确度为0.8177860061287026

jini上的最好准确度为0.8177987742594486

比起默认参数,经过参数的粗略调整后,模型在测试集上的准确度得到了明显提升

可以观察出当最大深度为3时,拟合效果较好,且两种划分情况准确度都十分相近

6.3 网格搜索调整参数

如果参数的取值范围很大,参数个数也很多,这么一个个参数人为的去慢慢尝试是非常消耗时间的,因此我们可以调用sklearn的GridSearchCV来帮助我们寻找合适的参数。

网格参数搜索的本质其实就是把每个参数的取值排列组合一个个帮我们尝试,并且返回交叉验证准确度最好的一组参数。

在调用网格参数搜索前最好先确定参数的大致范围,否则相当消耗时间

In [15]:

#网格搜索:能够帮助我们调整多个参数的技术---枚举

#网格搜索:能够帮助我们调整多个参数的技术---枚举

import numpy as np

from sklearn.model_selection import GridSearchCV

gini_threholds = np.linspace(0,0.5,20)

parameters = {'criterion':('gini','entropy')

,'splitter':('best','random')

,'max_depth':[*range(2,5)]

,'min_samples_leaf':[*range(1,10,2)]

# ,'min_impurity_decrease':np.linspace(0,0.5,20)

}

clf = DecisionTreeClassifier(random_state=25)

gs = GridSearchCV(clf,parameters,cv=10)

gs.fit(Xtrain,Ytrain)

In [16]:

gs.best_params_ #我们输入参数和参数取值中,最佳组合

Out [16]:

{'criterion': 'gini',

'max_depth': 4,

'min_samples_leaf': 1,

'splitter': 'random'}

用训练的参数导入模型

In [17]:

clf = DecisionTreeClassifier(random_state=20

,criterion='gini'

,max_depth=4

,min_samples_leaf=1

,splitter='random'

)

clf = clf.fit(Xtrain, Ytrain)

cross_val_score(clf,X,y,cv=10).mean()

Out [17]:

0.806511746680286

比之前稍差了点,这其实是因为GridSearchCV在评判的参数好坏的标准是把传入的训练集又分为了训练集和测试集,并通过交叉验证求平均找出准确率最好的参数组合;而之前的算法的准确率是直接用训练集训练并用全部数据集交叉验证的结果,因此两者在评判对象上有所不同,如果两者准确率相差不大,那就任选即可。

如果上面的解释没看懂,那就记住如果自己调试的参数和网格搜索结果相差不大,那说明你已经逼近了调参结果的上限,任选一个就好了。

7. 上传到kaggle查看得分

把官方的测试数据集进行预测并上传到官网

刚刚的模型是训练集经过处理才能使用的,因此测试集也要做同样处理。

In [18]:

test = pd.read_csv('Taitanic data/test.csv')

test.info()

Out [18]:

RangeIndex: 418 entries, 0 to 417

Data columns (total 11 columns):

PassengerId 418 non-null int64

Pclass 418 non-null int64

Name 418 non-null object

Sex 418 non-null object

Age 332 non-null float64

SibSp 418 non-null int64

Parch 418 non-null int64

Ticket 418 non-null object

Fare 417 non-null float64

Cabin 91 non-null object

Embarked 418 non-null object

dtypes: float64(2), int64(4), object(5)

memory usage: 36.0+ KB

发现和训练集不同的是‘Fare’特征有一个缺失值,这需要小心不能忘了处理

In [19]:

#把测试集预处理操作封装

def clean_data(data):

data = data.drop(['Cabin','Name','Ticket','PassengerId']

,axis=1

)

data['Age'] = data['Age'].fillna(data['Age'].mean())

data['Fare'] = data['Fare'].fillna(data['Fare'].mean()) #

data = data.dropna(axis=0)

data['Sex'] = (data['Sex'] == 'male').astype('int')

data['Embarked'] = data['Embarked'].map({'S':0,'C':1,'Q':2})

return data

In [20]:

test_data = clean_data(test)

res = pd.concat([test['PassengerId'],pd.DataFrame(clf.predict(test_data))],axis=1)

res.columns = ['PassengerId','Survived']

res.to_csv("result.csv",sep=',',index=False)

提交结果查看得分,top20%的baseline,还行

8 总结

完成了一次完整的kaggle还是很有成就感的,不过依然有很多瑕疵。

kaggle最重要的特征工程几乎被我一笔带过,数据没有经过严密的统计分析,有句话叫“特征工程决定了最后结果的上限,而机器学习算法只是在逼近这个上限”。特征上还有很多事情可以做,例如:

Age可以尝试Random forest、SVM等算法预测填充

Cabin可以保留,把缺失值当作一类,非缺失值当作一类

sibsp,parch也可以推测出一个人的年龄区间

sibsp,parch两个特征可以用一个新的特征“家庭成员数量”代替试试

… …

甚至尝试不同的模型,对于不同的模型又会有不同的数据处理方式,例如降为、归一化、One-hot编码等,如果把泰坦尼克号数据集的内容吃透对于其他数据集也能得心应手了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值