kaggle泰坦尼克号数据集—决策树python实现

回忆杀

先来一波回忆杀,沉迷于男女主的颜值自拔,当年的小李子的确是魅力四射啊!还记得那句经典的台词You jump,I jump,代表着永恒的爱情啊
在这里插入图片描述
先收住,等会再舔屏,我们今天不讲《泰坦尼克号》,主要讲泰坦尼克号。电影是根据真实故事改编而来的,1912年泰坦尼克号作为当时世界上最豪华、最庞大的客运轮船,在处女航中途与一座冰山相撞,大部分人不幸身亡,少部分人存活下来。因此本文想利用机器学习中的重要算法之一决策树(Decision Tree),根据乘客的数据(性别、年龄等)对其能否存活进行预测。如果在真实背景下,预测Jack和Rose能否存活幸存。

决策树是啥?

决策树都不知道?本仙女可没空和你吹牛。所谓决策树,其实是一种十分常用的分类方法。是一种监管学习方法,也就是给你一堆样本,每个样本都有一组属性和一个类别,这些类别是我们是已知的,也就是本案例中是否存活。通过决策树进行训练,那么就能够对新出现的乘客给出正确的分类啦。
决策树是在已知各种情况发生概率的基础上,通过构成决策树来求取净现值的期望值大于等于零的概率,评价项目风险,判断其可行性的决策分析方法。在机器学习中,决策树是一个预测模型,他代表的是对象属性与对象值之间的一种映射关系。Entropy = 系统的凌乱程度,使用算法ID3, C4.5和C5.0生成树算法使用熵。
给一个通俗易懂的例子吧,比如某银行要判断一个新客户是否可以贷款,根据历史客户数据生成决策树是酱紫的。那么我们先从根节点房产出发,如果该客户有房产,则可以贷款,若没有房产,再看其是否车辆,若有车辆,则可以贷款,若没有再看其年收入,以此类推,总能判断是否可以贷款。一眼就能看出这个图很像一棵树呢,所以就叫决策树啦。
在这里插入图片描述

泰坦尼克号数据集

首先来介绍下泰坦尼克号数据集吧,共收集到1309个样本,乘客的12个特征,其中Survived是因变量,是个二分类变量(存活和死亡),其他11个特征作为因变量,是不是刚好符合决策树算法的要求。

变量(变量解释)
Survived 存活情况(存活1,死亡0)
PassengerId 乘客编号
Pclass 船舱等级(1,2,3)
Name 乘客姓名
Sex 乘客性别
Age 乘客年龄
SibSp 同乘的兄弟姐妹/配偶数
Parch 同乘的父母/小孩数
Ticket 船票编号(字符串)
Fare 船票价格(0-500)
Cabin 乘客所在船舱
Embarked 乘客登船港口(S,C,Q)

其中891个作为训练集,418个作为测试集。需要的包和导入数据的Python代码都在这里啦。Padas中的concat函数就是把训练集和测试集合并起来了,方便后面统一分析。
用Python自带的函数sample抽5个样本悄悄看一下数据,index是抽取的样本所在的行数。其实我们拿到的数据是有缺失的,比如Cabin船舱。
在这里插入图片描述
在这里插入图片描述

Part3

下面就是特征工程了,来看看乘客的存活情况是否与单个因变量有关

性别sex

先看一下性别和存活情况的关系,女性的存活率为74.20%,男性的存活率仅为18.89%,可见女性确实是受保护的,存活率远远高于男性。女性优先在危难关头得到淋漓尽致的展现了。
在这里插入图片描述

船舱等级class

下面来看一下船舱等级的存活率图,等级一、二、三的存活率分别为 62.97%、47.28%、24.24%。代码只需要把上面代码的“Sex”换成“Pclass”,so easy这里就不附上了。
在这里插入图片描述

年龄age

再来看一下年龄和存活率的情况吧
在这里插入图片描述
可以看出,在6岁左右,存活(1)远远大于死亡(0),说明儿童相对保护的比较好,大多数是存活下来的。25岁左右的青年存活率要低于死亡率,更多年轻人会把生存机会留给老人和孩子。在60到80岁之间,存活率比较比死亡率要低,老人相对体力不够,存活比较困难。

Fare

数据处理

我们先来瞄一眼缺失值情况,数据集共包含1309条记录,其中训练集891条,测试集418条。
在这里插入图片描述
可以看到特征Age,Cabin,Embarked,Fare以及Ticket不全,包含缺失值,需要进行缺失值填补,其中Survived是否生存,就是我们研究的因变量,所以测试集全为缺失。

年龄Age

首先来看年龄,通过前面推文我们已经知道年龄是重要特征,因此其缺失值的能否正确填补对模型有较大影响。通过进一步分析可以发现,登船者的年龄与其同乘的兄弟姐妹/配偶数(SibSp)、同乘的小孩数(Parch)有一定关联。因此我们这里用与缺失年龄的乘客有一样SibSp、Parch的乘客的平均年龄来填补缺失值,如果这个值为空,那就用所有乘客的平均年龄来填补。

index_NaN_age = list(dataset["Age"][dataset["Age"].isnull()].index)
for i in index_NaN_age :
    age_med = dataset["Age"].median()
    age_pred = dataset["Age"][((dataset['SibSp'] == dataset.iloc[i]["SibSp"]) & (dataset['Parch'] == dataset.iloc[i]["Parch"]) & (dataset['Pclass'] == dataset.iloc[i]["Pclass"]))].median()
    if not np.isnan(age_pred) :
        dataset['Age'].iloc[i] = age_pred
    else :
        dataset['Age'].iloc[i] = age_med

船票价格Fare

接下来看船票价格与乘客存活率的关系,violin图的代码只需在箱线图基础上加参数kind=’violin’
在这里插入图片描述
可以看出,存活下来的的乘客(Survived=1)其船票价格在100附近的相对较多,整体来说,未存活的乘客船票价格相对较低。

dataset["Fare"] = dataset["Fare"].fillna(dataset["Fare"].median())
dataset["Fare"] = dataset["Fare"].map(lambda i: np.log(i) if i > 0 else 0)

船票价格的缺失值只有3个,我们就可以简单粗暴的用中位数进行填补啦。但需注意的是,极少数乘客的票价相当高,因此我们这里对大于0的票价取对数,缩小差距,更好建模。

登船港口Embarked

下面我们来看登船港口的存活率,并加入的性别做对比。总共有S、C、Q三个港口,可以看出,无论是男性还是女性,各个港口的存活率是有较大差距的。明显看出港口C的存活率最高。
在这里插入图片描述
因为登船港口仅有两个缺失,我们就直接用众数填补了。先用value_counts()函数对频数进行统计,可以看出三个港口登船人数最多的为S,也就是众数,就直接用S进行填补啦~
在这里插入图片描述
dataset[“Embarked”].value_counts()
dataset[“Embarked”] = dataset[“Embarked”].fillna(“S”)

名字Name

泰坦尼克号数据集的Name特征比较特殊,我们先看一下其前五行:
在这里插入图片描述
一眼看上去名字特征似乎没什么用处,但其实这里包含了一个重要特征:乘客的头衔,即Mr、Mrs这样的title,不同的头代表的身份地位不同,与其存活率应该有较大关系。这里我们首先把头衔信息提取出来,并命名为Title,作为数据集的新列。其中split函数就是按指定的字符对字符串进行分割。这里首先利用‘,’将姓和名分开,再用‘.’将头衔提出来。

dataset_title = [i.split(",")[1].split(".")[0].strip() for i in dataset["Name"]]#strip()去除首尾的空白
dataset["Title"] = pd.Series(dataset_title)
dataset["Title"].head()  

看一下提取的效果,一下就把我们想要的头衔提取出来了~
在这里插入图片描述
but由于头衔种类特别多,且很多头衔出现的频数很少,频数统计如图。
在这里插入图片描述

接下来用replace函数对出现次数少且相近的头衔进行替换。最后再将头衔Ms、Miss 、Mme、Mlle、Mrs归为一类,其他头衔单独归为一类。

dataset["Title"] = dataset["Title"].replace(['Lady', 'the Countess','Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
dataset["Title"] = dataset["Title"].map({"Master":0, "Miss":1, "Ms" : 1 , "Mme":1, "Mlle":1, "Mrs":1, "Mr":2, "Rare":3})
dataset["Title"] = dataset["Title"].astype(int)

家庭成员数

下面我们关注同乘的兄弟姐妹/配偶数(SibSp)与同乘的小孩数(Parch),因为这两个特征其实反映了乘客的同行的家庭成员数,因此我们新创建一个特征家庭成员数Fsize =SibSp + SibSp+1。创建之后再用lambda函数赋值为0和1。

dataset.drop(labels = ["Name"], axis = 1, inplace = True)

# Create a family size descriptor from SibSp and Parch
dataset["Fsize"] = dataset["SibSp"] + dataset["Parch"] + 1

# Create new feature of family size
dataset['Single'] = dataset['Fsize'].map(lambda s: 1 if s == 1 else 0)
dataset['SmallF'] = dataset['Fsize'].map(lambda s: 1 if  s == 2  else 0)
dataset['MedF'] = dataset['Fsize'].map(lambda s: 1 if 3 <= s <= 4 else 0)
dataset['LargeF'] = dataset['Fsize'].map(lambda s: 1 if s >= 5 else 0)

分类变量编码

最后再将所有分类变量进行编码

dataset = pd.get_dummies(dataset, columns = ["Title"])
dataset = pd.get_dummies(dataset, columns = ["Embarked"], prefix="Em")

模型与预测

处理好的数据就可以进行建模和预测了(爱学习的小同学不要着急,后续会继续讲数据的具体整理过程),sklearn包里面有许多分类算法,我们导出里面的DecisionTreeClass就可以啦。代码附上,其中Y_train,X_train分别为训练集的因变量和自变量,X_test为测试集的因变量。

clf = tree.DecisionTreeClassifier(random_state=2)

train = dataset[:len(train)]
test = dataset[891:]
train["Survived"] = train["Survived"].astype(int)

Y_train = train["Survived"]
X_train = train.drop(labels = ["Survived"],axis = 1)
X_train = X_train.drop(labels = ["Ticket"],axis = 1)
X_test = test.drop(labels = ["Ticket"],axis = 1)

X_train.head()
clf.fit(X_train,Y_train) 
y_pred = clf.predict(X_test)
X_train.isnull()
`

最后回归电影《泰坦尼克号》,将男女主的数据录入测试集,有部分信息无法得知,用样本数据进行填补。最后预测得到Jack死亡,Rose生存,与电影的结局是一致的。有爱学习的小朋友可能会说决策树预测的不准,那么后续推文会再介绍其它机器学习的算法,再进行预测,乖乖等着吧。
最后的最后,学习太辛苦了,再来欣赏一下男女主的神仙颜值吧。
在这里插入图片描述
The End 下面是全部代码

#data analysis libraries 
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

#ignore warnings
import warnings
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
#import train and test CSV files
train = pd.read_csv(r"E:\gaojian\gaojian\train.csv")
test = pd.read_csv(r"E:\gaojian\gaojian\test.csv")
dataset=pd.concat([train, test])
dataset.info()

#take a look at the training data
train.describe(include="all")
#get a list of the features within the dataset
print(train.columns)
#see a sample of the dataset to get an idea of the variables
w=train.sample(5)
w.to_csv("Decision Tree.csv")
#draw a bar plot of survival by sex
font1 = {'family' : 'Times New Roman',
'weight' : 'normal',
'size'   : 15,
}
font2 = {'family' : 'Times New Roman',
'weight' : 'normal',
'size'   : 19}

  '''特征工程'''
sns.set()
g = sns.barplot(x="Sex", y="Survived", data=train)
plt.yticks(fontproperties = 'Times New Roman', size = 14)
plt.xticks(fontproperties = 'Times New Roman', size = 14)
plt.xlabel('Sex',font2)
plt.ylabel('Survived',font2)
plt.tight_layout()
plt.savefig('性别.png',dpi=300 )
#print percentages of females vs. males that survive

#draw a bar plot of survival by Pclass
sns.set()
g = sns.barplot(x="Pclass", y="Survived", data=train)
plt.yticks(fontproperties = 'Times New Roman', size = 14)
plt.xticks(fontproperties = 'Times New Roman', size = 14)
plt.xlabel('Pclass',font2)
plt.ylabel('Survived',font2)
plt.tight_layout()
plt.savefig('Pclass.png',dpi=300 )
#print percentage of people by Pclass that survived
print("Percentage of Pclass = 1 who survived:", train["Survived"][train["Pclass"] == 1].value_counts(normalize = True)[1]*100)

sns.set()
g = sns.factorplot('Pclass','Survived',hue='Sex',data=train, prop=font1)
plt.yticks(fontproperties = 'Times New Roman', size = 14)
plt.xticks(fontproperties = 'Times New Roman', size = 14)
plt.xlabel('Pclass',font2)
plt.ylabel('Survived',font2)
#plt.legend( prop=font1)
plt.tight_layout()
plt.savefig('Pclass.png',dpi=300 )

sns.set()
g = sns.kdeplot(train["Age"][(train["Survived"] == 0)], color="Red", shade = True)
g = sns.kdeplot(train["Age"][(train["Survived"] == 1)], ax =g, color="Blue", shade= True)
g = g.legend(["Survived=0","Survived=1"])
plt.yticks(fontproperties = 'Times New Roman', size = 14)
plt.xticks(fontproperties = 'Times New Roman', size = 14)
plt.xlabel('Age',font2)
plt.ylabel('Survived',font2)
plt.legend( prop=font1)
plt.tight_layout()
plt.savefig('Age.png',dpi=300 )



  '''特征工程新'''
 '''Fare''' 
sns.set()
g = sns.factorplot(x="Survived", y = "Fare",data = train, kind="violin")
plt.yticks(fontproperties = 'Times New Roman', size = 14)
plt.xticks(fontproperties = 'Times New Roman', size = 14)
plt.ylabel('Fare',font2)
plt.xlabel('Survived',font2)
plt.tight_layout()
plt.savefig('Fare.png',dpi=300 )

dataset.info()
#Fill Fare missing values with the median value
dataset["Fare"] = dataset["Fare"].fillna(dataset["Fare"].median())
#取对数 使其更好拟合
dataset["Fare"] = dataset["Fare"].map(lambda i: np.log(i) if i > 0 else 0)

#Embarked
sns.set()
g = sns.factorplot('Embarked','Survived',hue='Sex',data=train, prop=font1)
plt.yticks(fontproperties = 'Times New Roman', size = 14)
plt.xticks(fontproperties = 'Times New Roman', size = 14)
plt.xlabel('Embarked',font2)
plt.ylabel('Survived',font2)
#plt.legend( prop=font1)
plt.tight_layout()
plt.savefig('Embarked.png',dpi=300 )

#Fill Embarked nan values of dataset set with 'S' most frequent value
dataset["Embarked"].value_counts()
dataset["Embarked"] = dataset["Embarked"].fillna("S")

'''sex'''
# convert Sex into categorical value 0 for male and 1 for female
dataset["Sex"] = dataset["Sex"].map({"male": 0, "female":1})

'''age'''
index_NaN_age = list(dataset["Age"][dataset["Age"].isnull()].index)
for i in index_NaN_age :
    age_med = dataset["Age"].median()
    age_pred = dataset["Age"][((dataset['SibSp'] == dataset.iloc[i]["SibSp"]) & (dataset['Parch'] == dataset.iloc[i]["Parch"]) & (dataset['Pclass'] == dataset.iloc[i]["Pclass"]))].median()
    if not np.isnan(age_pred) :
        dataset['Age'].iloc[i] = age_pred
    else :
        dataset['Age'].iloc[i] = age_med

'''name'''       
dataset_title = [i.split(",")[1].split(".")[0].strip() for i in dataset["Name"]]#strip()去除首尾的空白
dataset["Title"] = pd.Series(dataset_title)
dataset["Title"].head()  

# Convert to categorical values Title 
dataset["Title"] = dataset["Title"].replace(['Lady', 'the Countess','Countess','Capt', 'Col','Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
dataset["Title"] = dataset["Title"].map({"Master":0, "Miss":1, "Ms" : 1 , "Mme":1, "Mlle":1, "Mrs":1, "Mr":2, "Rare":3})
dataset["Title"] = dataset["Title"].astype(int)

'''Fsize'''
# Drop Name variable
dataset.drop(labels = ["Name"], axis = 1, inplace = True)

# Create a family size descriptor from SibSp and Parch
dataset["Fsize"] = dataset["SibSp"] + dataset["Parch"] + 1

# Create new feature of family size
dataset['Single'] = dataset['Fsize'].map(lambda s: 1 if s == 1 else 0)
dataset['SmallF'] = dataset['Fsize'].map(lambda s: 1 if  s == 2  else 0)
dataset['MedF'] = dataset['Fsize'].map(lambda s: 1 if 3 <= s <= 4 else 0)
dataset['LargeF'] = dataset['Fsize'].map(lambda s: 1 if s >= 5 else 0)

# convert to indicator values Title and Embarked 
dataset = pd.get_dummies(dataset, columns = ["Title"])
dataset = pd.get_dummies(dataset, columns = ["Embarked"], prefix="Em")

# Replace the Cabin number by the type of cabin 'X' if not
dataset["Cabin"] = pd.Series([i[0] if not pd.isnull(i) else 'X' for i in dataset['Cabin'] ])
dataset = pd.get_dummies(dataset, columns = ["Cabin"],prefix="Cabin")



## Treat Ticket by extracting the ticket prefix. When there is no prefix it returns X. 
Ticket = []
for i in list(dataset.Ticket):
    if not i.isdigit() :
        Ticket.append(i.replace(".","").replace("/","").strip().split(' ')[0]) #Take prefix
    else:
        Ticket.append("X")
dataset["Ticket"] = Ticket
dataset["Ticket"].head()

# Create categorical values for Pclass
dataset["Pclass"] = dataset["Pclass"].astype("category")
dataset = pd.get_dummies(dataset, columns = ["Pclass"],prefix="Pc")

# Drop useless variables 
dataset.drop(labels = ["PassengerId"], axis = 1, inplace = True)
# Cross validate model with Kfold stratified cross val
#from sklearn.model_selection import GridSearchCV, cross_val_score, StratifiedKFold, learning_curve
from sklearn.tree import DecisionTreeClassifier
#kfold = StratifiedKFold(n_splits=10)
#classifier=DecisionTreeClassifier(random_state=2)

#cross_val_score(classifier, X_train, y = Y_train, scoring = "accuracy", cv = kfold, n_jobs=4)

'''  DecisionTreeClassifier  '''
'''Titanic Top 4% with ensemble modeling'''
from sklearn.metrics import confusion_matrix
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve, auc  ###计算roc和auc
from sklearn import cross_validation
from sklearn import tree
clf = tree.DecisionTreeClassifier(random_state=2)

train = dataset[:len(train)]
test = dataset[891:]
train["Survived"] = train["Survived"].astype(int)

Y_train = train["Survived"]
X_train = train.drop(labels = ["Survived"],axis = 1)
X_train = X_train.drop(labels = ["Ticket"],axis = 1)
X_test = test.drop(labels = ["Ticket"],axis = 1)
#a=dataset.drop(labels = ["Ticket"], axis = 1, inplace = True)
#a=dataset.drop(labels = ["Cabin"], axis = 1, inplace = True)

X_train.head()
clf.fit(X_train,Y_train) 
y_pred = clf.predict(X_test)
X_train.isnull()


发布了16 篇原创文章 · 获赞 9 · 访问量 1043

猜你喜欢

转载自blog.csdn.net/qq_42871249/article/details/102720018