Kaggle实战:随机森林预测泰坦尼克生存率

一、项目背景和分析需求的提出

    泰坦尼克号出事后,收集了乘客的各项数据,包括:
PassengerId、Survived、Pclass、Name、Sex、Age、SibSp、Parch、Ticket、Fare、Cabin、Embarked。

要求用这些数据训练一个能够判断乘客是否生还的二分类器。

二、数据预处理

1.导入数据,熟悉数据

这是进行分析的第一步,我们需要大概了解数据集都有哪些字段,都是什么类型的变量,记录是否完整等。

import pandas as pd  

#用pandas库的read_csv()来读取文件,其中('')中的内容如果不在同一个环境下,用绝对路径。
titanic = pd.read_csv('train.csv')

#不包括列名显示前5行,系统从0开始计数
print(titanic.head())

#显示数据的各项基本数字特征:计数、均值、方差等等
print(titanic.describe())

得到结果:

PassengerId  Survived  Pclass  \
0            1         0       3   
1            2         1       1   
2            3         1       3   
3            4         1       1   
4            5         0       3   

                                                Name     Sex   Age  SibSp  \
0                            Braund, Mr. Owen Harris    male  22.0      1   
1  Cumings, Mrs. John Bradley (Florence Briggs Th...  female  38.0      1   
2                             Heikkinen, Miss. Laina  female  26.0      0   
3       Futrelle, Mrs. Jacques Heath (Lily May Peel)  female  35.0      1   
4                           Allen, Mr. William Henry    male  35.0      0   

   Parch            Ticket     Fare Cabin Embarked  
0      0         A/5 21171   7.2500   NaN        S  
1      0          PC 17599  71.2833   C85        C  
2      0  STON/O2. 3101282   7.9250   NaN        S  
3      0            113803  53.1000  C123        S  
4      0            373450   8.0500   NaN        S  

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

2.缺失值的处理。

    查看每一个变量的是否有缺失:

titanic.count()

得到结果:

PassengerId    891
Survived       891
Pclass         891
Name           891
Sex            891
Age            714
SibSp          891
Parch          891
Ticket         891
Fare           891
Cabin          204
Embarked       889
dtype: int64

    可知,除了Age、Cabin、Embarked三个变量外,其他变量均有891个记录,所以需要对这三个有缺失值的变量进行处理。

2.1  缺失比例过高的变量处理

    Cabin只有204条记录,缺失值占比太高,直接舍弃。

2.2  数值型变量缺失值补全

    数值型变量可选择该变量的各统计特征补全,如:平均值、众数、最大值、最小值等。

    这里选择用平均值补全Age缺失的部分。

#数据预处理:1.将有缺失值的列补全。
titanic["Age"] = titanic["Age"].fillna(titanic["Age"].median())
#Age列有很多的缺失值,用.fillna(xxx)用xxx填充Age列,并将结果赋给Age列
print(titanic["Age"].count())

得到结果:

    891

2.3  字符型变量缺失值补全

    变量Embarked的类型为字符型,我们可以用数量最多的值补全缺失值。先看一下Embarked的各个取值的数量。

#看一下,哪个值的数量最多
titanic.Embarked.value_counts()

得到结果:

S    644
C    168
Q     77
Name: Embarked, dtype: int64

    可知,'S'的值最多,我们用'S'来补全缺失的部分。

#统计得出S值最多,所以拿S填充缺失的部分
titanic["Embarked"] = titanic["Embarked"].fillna('S')
print(titanic["Age"].count())
得到结果:

    891

3.字符型变量转换为数值型变量。

    字符型变量不利于计算机处理,我们需要把字符型变量转换成数值型变量。

3.1  处理变量Sex

    对于变量Sex,先观察它有哪些可能值。

#打印Sex列一共有几种可能的值
print (titanic["Sex"].unique())

得到结果:

['male' 'female']

    将0赋给male,1赋给female。

titanic.loc[titanic["Sex"] == "male", "Sex"] = 0
titanic.loc[titanic["Sex"] == "female", "Sex"] = 1

3.2  处理变量Embarked

    观察可能值。

print(titanic["Embarked"].unique())
得到结果:
['S' 'C' 'Q' nan]

    令'S'= 0 ,'C'= 1, 'Q'= 2

titanic.loc[titanic["Embarked"] == "S", "Embarked"] = 0
titanic.loc[titanic["Embarked"] == "C", "Embarked"] = 1
titanic.loc[titanic["Embarked"] == "Q", "Embarked"] = 2

4.准备训练数据集

4.1  挑选变量

    选择"Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"七个变量作为训练分类器的数据集。
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
X = titanic[predictors]
y = titanic["Survived"]

4.2  数据标准化

from sklearn import preprocessing
X = preprocessing.scale(X)

    至此,数据集准备完毕,(X,y)。

三、随机森林求解。

1.引入交叉验证

    将数据集分为4份做交叉验证。

from sklearn import cross_validation
kf = cross_validation.KFold(titanic.shape[0], n_folds=4, random_state=3)

2.随机森

    从sklearn中导入随机森林分类器,计算分类得分。

from sklearn.ensemble import RandomForestClassifier
RFC = RandomForestClassifier(n_estimators=80, min_samples_split=6, min_samples_leaf=1)
RFCscores = cross_validation.cross_val_score(RFC, X, y, cv=kf)
print(RFCscores.mean())

得到结果:

    0.8305508423221427

3.随机森林改进

    随机森林分类器中的树的个数,最小样本数及最小子叶数都是可以修改的。我们可以通过循环尝试找出最佳参数。这里以树的个数为例。

from sklearn.ensemble import RandomForestClassifier
a = []
b = []
for i in range(1,100):
    RFC = RandomForestClassifier(n_estimators=i, min_samples_split=6, min_samples_leaf=1)
    RFCscores = cross_validation.cross_val_score(RFC, X, y, cv=kf)
    a.append(RFCscores.mean())
    b.append(i)
print(max(a))
print(a.index(max(a))+1)

得到结果:

 
0.8406455783137398
34

作折线图看一下树的个数与得分之间的关系。

import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot(b,a)
plt.show()
得到结果:

可以看到,当树的数量为34时,得分最高达到84%。

四、特征工程:提炼特征,重构数据集

1.尝试构造可能与生还有关的特征(自由发挥想象力,一个充满玄学的过程)。

1.1  家庭规模大小

原始数据集中给出了兄弟姐妹SibSp和父母小孩Parch的数量,将这俩个数据加总在一起,可以得出每个乘客的家庭规模大小。

titanic["FamilySize"] = titanic["SibSp"] + titanic["Parch"]

1.2  名字的长度

原始数据中给出了每个乘客的名字,如何利用这一变量?可能名字的长度和生还率有关。

titanic["NameLength"] = titanic["Name"].apply(lambda x: len(x))

1.3  名字的称谓

外国人对于称谓比较严格,或许称谓和生还率也有关系。

#用re.search来匹配称谓
import re
def get_title(name):
    title_search = re.search(' ([A-Za-z]+)\.', name)
    if title_search:
        return title_search.group(1)
    return ""

#将称谓保存在titles中
titles = titanic["Name"].apply(get_title)

#将字符型的称谓转换为数值型
title_mapping = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Dr": 5, "Rev": 6, "Major": 7, "Col": 7, "Mlle": 8, "Mme": 8, "Don": 9, "Lady": 10, "Countess": 10, "Jonkheer": 10, "Sir": 9, "Capt": 7, "Ms": 2}
for k,v in title_mapping.items():
    titles[titles == k] = v

#将转换后的称谓添加到原始数据集中
titanic["Title"] = titles

1.4  欣赏一下新构建的数据集都有啥

titanic.head()

得到结果:

PassengerId	Survived     Pclass	    Name	                                      Sex	Age	SibSp	Parch	Ticket	            Fare	Cabin	Embarked	FamilySize	NameLength	Title
0	1	0	        3	Braund, Mr. Owen Harris	                                0	22.0	1	0	A/5 21171	    7.2500	NaN	  0	            1	              23	1
1	2	1               1	Cumings, Mrs. John Bradley (Florence Briggs Th...	1	38.0	1	0	PC 17599	    71.2833	C85	  1	            1	              51	3
2	3	1               3	Heikkinen, Miss. Laina	                                1	26.0	0	0	STON/O2.3101282	    7.9250	NaN	  0	            0	              22	2
3	4	1	        1	Futrelle, Mrs. Jacques Heath (Lily May Peel)	        1	35.0	1	0	113803	            53.1000	C123	  0	            1	              44	3
4	5	0	        3	Allen, Mr. William Henry	                        0	35.0	0	0	373450	            8.0500	NaN	  0	            0	              24	1

2.用添加了3个特征的数据集重新训练随机森林分类器

#创建数据集
predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked","FamilySize", "Title", "NameLength"]
X = titanic[predictors]
y = titanic["Survived"]

#数据标准化
from sklearn import preprocessing
import numpy as np
X = preprocessing.minmax_scale(X,feature_range=(0,1))

#引入交叉验证
from sklearn import cross_validation
kf = cross_validation.KFold(titanic.shape[0], n_folds=4, random_state=3)

#随机森林求解
from sklearn.ensemble import RandomForestClassifier
RFC = RandomForestClassifier(n_estimators=56, min_samples_split=6, min_samples_leaf=1)
RFCscores = cross_validation.cross_val_score(RFC, X, y, cv=kf)
print(RFCscores.mean())

得到结果:

0.8327929947885104
#随机森林改进
from sklearn.ensemble import RandomForestClassifier
a = []
b = []
for i in range(1,100):
    RFC = RandomForestClassifier(n_estimators=i, min_samples_split=6, min_samples_leaf=1)
    RFCscores = cross_validation.cross_val_score(RFC, X, y, cv=kf)
    a.append(RFCscores.mean())
    b.append(i)
print(max(a))
print(a.index(max(a))+1)

#改进效果图
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot(b,a)
plt.show()

得到结果:

0.8462560093726013
54

    可以看出结果比构造特征之前的结果要提升了0.6%。

3.特征重要性

    有时候并不是每一个特征都对分类结果产生一个好的影响,可能去掉一些变量反而能得到更好的结果。这就需要筛选比较重要的特征。
from sklearn.feature_selection import SelectKBest, f_classif
#选择特种中最好的k个
selector = SelectKBest(f_classif, k=6)
selector.fit(X, y)
#将结果映射为容易观察的区间
scores = -np.log10(selector.pvalues_)
#画条形图
plt.bar(range(len(predictors)), scores)
plt.xticks(range(len(predictors)), predictors, rotation='vertical')
plt.show()

得到结果:


    可以看出Age、SibSp、Parch、FamilySize对生还的影响不大。用前6个变量训练随机森林分类器,看一下会不会有更好的结果。
#创建数据集
predictors = ["Pclass", "Sex", "Fare", "Embarked", "Title", "NameLength"]
X = titanic[predictors]
y = titanic["Survived"]

#数据标准化
from sklearn import preprocessing
import numpy as np
X = preprocessing.minmax_scale(X,feature_range=(0,1))

#引入交叉验证
from sklearn import cross_validation
kf = cross_validation.KFold(titanic.shape[0], n_folds=4, random_state=3)

#随机森林求解
from sklearn.ensemble import RandomForestClassifier
RFC = RandomForestClassifier(n_estimators=56, min_samples_split=6, min_samples_leaf=1)
RFCscores = cross_validation.cross_val_score(RFC, X, y, cv=kf)
print(RFCscores.mean())

得到结果:

0.8237991354583283
    好像结果并没有变好,看一下改进后的。
#随机森林改进

from sklearn.ensemble import RandomForestClassifier
a = []
b = []
for i in range(1,100):
    RFC = RandomForestClassifier(n_estimators=i, min_samples_split=6, min_samples_leaf=1)
    RFCscores = cross_validation.cross_val_score(RFC, X, y, cv=kf)
    a.append(RFCscores.mean())
    b.append(i)
print(max(a))
print(a.index(max(a))+1)
#print(RFCscores.mean())
#改进效果图
import matplotlib.pyplot as plt
fig = plt.figure()
plt.plot(b,a)
plt.show()

得到结果:

0.8350250474689936
44

好吧,说明有时候变量太少,结果也不会很好。

五、还想提高准确率怎么办

做到这一步,随机森林的分类器真的已经尽力了。如果还嫌分不高,想要再往上走一走有什么办法呢?

第一,可以改变分类器,随机森林做不到的事儿,其算法可以做到,其他算法做不到,还有集成算法在后面等着,再不行还有深度学习的算法。

第二,重新构造特征,多尝试几种可能性,特种工程做得好,准确率绝对低不了,低 不 了~。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值