泰坦尼克号的名单包括统计到的人员名单,包括人员的ID,是否幸存,仓位(1,2,3以及无座),姓名,性别,年龄等信息,截图如下:
本文将用Python对此样本数据进行一些简单的处理及应用。
首先用Spyder载入了泰坦尼克号的CSV数据文件,并打印了一下列名与样本个体数
train = pd.read_csv('D:/PythonPractice/titanic/train.csv')
print(train.columns.values.tolist()
print(len(train))
['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked']
891
从数据上并不能看出性别年龄等特征与是否幸存的关系。现在利用透视表查看仓位等级、性别与存活率的关系:
class_survived= train.pivot_table(index="Pclass",values="Survived")#仓位等级与存活率
sex_survived=train.pivot_table(index="Sex",values="Survived")#性别与存活率
SurvivedPclass
1 0.629630
2 0.472826
3 0.242363
Survived
Sex
female 0.742038
male 0.188908
这里发现仓位等级越高存活率越大,并且女性的存活率要远高于男性。
接下来利用绘图工具matplot的柱形图简单统计了一下年龄与存活率的关系:
age=train["Age"]
less5 =train[age<=5]
bigger5 =train[5<age]
less15=train[age<15]
beyond60=train[age>60]
percent5=len(less5[less5["Survived"]==1])/len(less5)
percent15=len(less15[less15["Survived"]==1])/len(less15)
percentB5=len(bigger5[bigger5["Survived"]==1])/len(bigger5)
percentbeyond60=len(beyond60[beyond60["Survived"]==1])/len(beyond60)
x=["<5","<15",">5",">60"]
y=[percent5,percent15,percentB5,percentbeyond60]
plt.bar(x,y)
从图中可以看出,小于五岁的孩子存活率最高,15岁的次之。而大于60岁的存活率最低。
之后来看一下家庭成员数与存活率的关系:
train["FamilySize"]=train["SibSp"]+train["Parch"]#家庭成员数由这两个列组成,新建列FamilySize
size=train[["FamilySize","Survived"]]
size1=size[size["FamilySize"]==1]
size23= size[size["FamilySize"].apply(lambda x: 1<x<4)== True]
size45= size[size["FamilySize"].apply(lambda x: 3<x<6)== True]
size5plus=size[size["FamilySize"]>=5]
survivdPercent1=len(size1[size1["Survived"]==1])/len(size1)#计算各个家庭数目及存活率
survivdPercent23=len(size23[size23["Survived"]==1])/len(size23)
survivdPercent45=len(size45[size45["Survived"]==1])/len(size45)
survivdPercent5plus=len(size5plus[size5plus["Survived"]==1])/len(size5plus)
x=["1","23","45","5 plus"]
y=[survivdPercent1,survivdPercent23,survivdPercent45,survivdPercent5plus]
plt.bar(x,y)
发现家庭成员数与存活率是有关系的。
所以从以上分析得出结论,存活率与年龄,性别,仓位等级有一定联系。接下来,就利用Python库中的随机森林模型对样本进行分析:
1. 要做的事情第一步是处理缺失值,以保证它对结果没有影响:
#train["Age"]=train["Age"].fillna(train["Age"].median())#填充年龄空行
train=train.dropna(subset=["Age"])#删除年龄空行
可以用年龄的中间值填补空行,或者直接剔除年龄空值。如果样本量非常巨大,那么少量地删除个体对结果的影响是非常小的。
2. 由于Python库处理数值比较方便,所以这里将男女表示为1和0
train.loc[train["Sex"]=="male","Sex"]=1#用0和1代表男女
train.loc[train["Sex"]=="female","Sex"] = 0
3. 声明特性列名
predictors=["Sex","Age","Pclass","FamilySize"]
4. 随机森林分类器
随机森林是由多个决策树组成,决策树是根据各个特性对结果的影响从大到小排列,逐一排查并最终确定最终结果。
例如在这里,对是否存活影响最大的因素为性别,那么建立的决策树的根节点就会判断此人是男人还是女人。之后再根据其他因素最终得出是否幸存。
但是决策树并不是分支越多越好,这样会导致叶子节点的个体个数过少,导致过拟合。所以在建立决策树时,会根据不同情况对决策树进行限制,例如限制节点深度、限制叶子节点的个数、叶子节点的最少样本数等。
在这里,随机森林就是由多个决策树组成。他可以自动给出哪些特性比较重要,并且删除对结果没有影响或者影响极小的特性(对特性加噪并检验对结果影响大小)。
此处声明一个随机森林模型:
alg=RandomForestClassifier(random_state=2,n_estimators=5,min_samples_split=3,min_samples_leaf=1)
-random_state为随机种子,便于以后生成相同的随机数
-n_estimators为决策树个数
-min_samples_split为分割内部节点所需要的最小样本数量
-min_samples_leaf为节点最小叶子数
这里有大神为随机森林参数的详细介绍:点击打开链接
接下来声明交叉验证:
交叉验证会将训练样本分为多份(这里n_fold=5),它将会用1,2,3,4来预测5并用5检验;用1,2,3,5来预测4并用4检验...
交叉验证可以减少数据中缺失值或不准确值对结果的影响。
kf=cross_validation.KFold(train.shape[0],n_folds=5,random_state=1,shuffle= True)
-train.shape[0]为观察样本个数
-n_folds为交叉个数
-shuffle为是否打乱数据
接下来看一下交叉验证的结果如何:
scores=cross_validation.cross_val_score(alg, train[predictors], train["Survived"], cv=kf)#cv:代表不同的cross validation的方法
print(scores.mean())
结果为:0.7689254407564267
所以模型的预测成功率只有0.77,对于一个二分类问题并不是一个好的预测成功率。
为了得到一个更好的预测,我将模型的参数重新设置为n_estimators=100,min_samples_split=3,min_samples_leaf=2
结果为:0.8011326701467546
用修改后的模型进行预测,计算准确率
alg.fit(train[predictors],train["Survived"])
test=test.dropna(subset=["Age"])
test["FamilySize"]=test["SibSp"]+test["Parch"]
test.loc[test["Sex"]=="male","Sex"]=1#用0和1代表男女
test.loc[test["Sex"]=="female","Sex"] = 0
test["Predic"]= alg.predict(test[predictors]);
lenth=len(test)
accuracy=len(test[test["Predic"]==test["Survived"]])/len(test)
结果为:0.822289156626506
用混淆矩阵查看预测情况:
mat=confusion_matrix(test["Survived"],test["Predic"])
print(mat)
结果为:
[[175 30][ 29 98]]
0.822的预测效果一般,但是在对原始数据加强分析、加入更多特征、加入更多数据后,模型会有更高的准确率。
参考资料: