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

匿名 (未验证) 提交于 2019-12-03 00:25:02

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

    泰坦尼克号出事后,收集了乘客的各项数据,包括:
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

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

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

得到结果:

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

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

得到结果:

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

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

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

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

得到结果:

['male' 'female']

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

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

4.准备训练数据集

predictors = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"] X = titanic[predictors] y = titanic["Survived"]

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

三、随机森林求解。

1.引入交叉验证

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

2.随机森

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.尝试构造可能与生还有关的特征(自由发挥想象力,一个充满玄学的过程)。

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

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

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

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

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

#用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

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

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

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

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

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

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




易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!