手记

Kaggle入门项目,泰坦尼克号幸存者

泰坦尼克号幸存者项目是kaggle的入门项目,我先用python的matplotlib库对数据进行了可视化,初步探索后对数据进行了清洗,然后建立了逻辑回归模型对测试集进行了预测,kaggle得分是0.76076。


  1. 对数据进行统计并可视化

import pandas as pd
import numpy as np
data_train=pd.read_csv("D:/Titanic/data/train.csv")
print(data_train.info())#查看数据缺失情况
print(data_train.describe())#查看数据基本统计信息

输出为:


    用info函数来查看数据缺失信息。这艘船共有891个乘客,每个乘客都有12个属性。其中Age只有714个人有信息,缺失177个数据,而Cabin(客舱)则只有204个数据。

    用describe函数来查看基本的统计信息。发现幸存者占乘客的2/5,乘客平均年龄是29岁。为了进一步的来分析数据,我用matplotlib函数对这些数据进行了可视化。

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pylab import *
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
data_train=pd.read_csv("D:/Titanic/data/train.csv")
#查看各乘客等级的获救情况
survived_0=data_train.Pclass[data_train.Survived==0].value_counts()
survived_1=data_train.Pclass[data_train.Survived==1].value_counts()
df=pd.DataFrame({'获救':survived_1,'未获救':survived_0})
df.plot(kind='bar',stacked=True)
plt.title('各船舱乘客获救情况')
plt.xlabel('船舱等级')
plt.ylabel('人数')

#查看性别的获救情况
survived_0=data_train.Sex[data_train.Survived==0].value_counts()
survived_1=data_train.Sex[data_train.Survived==1].value_counts()
df2=pd.DataFrame({'获救':survived_1,'未获救':survived_0})
df2.plot(kind='bar',stacked=True)
plt.title('男女乘客获救情况')
plt.xlabel('性别')
plt.ylabel('人数')

# #查看各船舱级别下的男女获救情况(方法一)
# fig=figure()
# fig.add_subplot(131)
# survived_0_one=data_train.Sex[data_train.Survived==0][data_train.Pclass==1].value_counts()
# survived_1_one=data_train.Sex[data_train.Survived==1][data_train.Pclass==1].value_counts()
# df2=pd.DataFrame({'获救':survived_1_one,'未获救':survived_0_one})
# df2.plot(kind='bar',stacked=True)
# plt.title('头等舱')
# plt.xlabel('性别')
# plt.ylabel('人数')
# fig.add_subplot(132)
# survived_0_two=data_train.Sex[data_train.Survived==0][data_train.Pclass==2].value_counts()
# survived_1_two=data_train.Sex[data_train.Survived==1][data_train.Pclass==2].value_counts()
# df4=pd.DataFrame({'获救':survived_1_two,'未获救':survived_0_two})
# df4.plot(kind='bar',stacked=True)
# plt.title('二等舱')
# plt.xlabel('性别')
# plt.ylabel('人数')
# fig.add_subplot(133)
# survived_0_three=data_train.Sex[data_train.Survived==0][data_train.Pclass==3].value_counts()
# survived_1_three=data_train.Sex[data_train.Survived==1][data_train.Pclass==3].value_counts()
# df5=pd.DataFrame({'获救':survived_1_three,'未获救':survived_0_three})
# df5.plot(kind='bar',stacked=True)
# plt.title('三等舱')
# plt.xlabel('性别')
# plt.ylabel('人数')


#查看各船舱级别下的男女获救情况(方法二)
fig=figure()
plt.subplot(141)
data_train.Survived[data_train.Sex=='female'][data_train.Pclass==3].value_counts().sort_index().plot(kind='bar',color='pink')
plt.xticks(arange(2),['未获救','获救'])
plt.yticks(arange(0,301,50))
plt.legend(['低等舱/女生'],loc='best')
plt.subplot(142)
data_train.Survived[data_train.Sex=='female'][data_train.Pclass!=3].value_counts().sort_index().plot(kind='bar',color='hotpink')
plt.xticks(arange(2),['未获救','获救'])
plt.yticks(arange(0,301,50))
plt.legend(['高等舱/女生'],loc='best')
plt.subplot(143)
data_train.Survived[data_train.Sex=='male'][data_train.Pclass==3].value_counts().sort_index().plot(kind='bar',color='lightsteelblue')
plt.xticks(arange(2),['未获救','获救'])
plt.yticks(arange(0,301,50))
plt.legend(['低等舱/男生'],loc='best')
plt.subplot(144)
data_train.Survived[data_train.Sex=='male'][data_train.Pclass!=3].value_counts().sort_index().plot(kind='bar',color='cornflowerblue')
plt.xticks(arange(2),['未获救','获救'])
plt.yticks(arange(0,301,50))
plt.legend(['高等舱/男生'],loc='best')
fig.tight_layout()
plt.show()

从这张图中可以看出高等舱获救的人最多,获救机会跟个人财力是有关系的。



从总体来看,女性获救的机会比男生大。我猜想救援时也遵循了女士优先的原则。正常情况下是女士和小孩优先,所以年龄对获救机会也有影响,为了验证,接下来继续分析。

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pylab import *
fig=figure()
fig.set(alpha=0.2)
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
data_train=pd.read_csv("D:/Titanic/data/train.csv")

plt.subplot(341)
data_train.Survived.value_counts().plot(kind='bar')
plt.title("获救情况(1为获救)")
plt.ylabel("人数")

plt.subplot(342)
data_train.Pclass.value_counts().plot(kind='bar')
plt.title("乘客等级分布")
plt.ylabel("人数")

plt.subplot(344)
y=data_train.Age
x=data_train.Survived
plt.scatter(x,y)
plt.title("按年龄看获救分布(1)为获救")
plt.ylabel("年龄")

plt.subplot(312)
y=data_train.Age.value_counts()
y.sort_index().plot(kind='bar')
plt.xlabel("年龄")
plt.ylabel("人数")
plt.title("各年龄的乘客人数")

plt.subplot(313)
data_train.Age[data_train.Pclass==1].plot(kind='kde')#密度图
data_train.Age[data_train.Pclass==2].plot(kind='kde')
data_train.Age[data_train.Pclass==3].plot(kind='kde')
plt.xlabel("年龄")
plt.ylabel("密度")
plt.title("各等级的乘客年龄分布")
plt.legend(('头等舱','二等舱','三等舱'),loc='best')

plt.subplot(343)
data_train.Embarked.value_counts().plot(kind='bar')
plt.title("各登船口岸上船人数")
plt.ylabel("人数")  
#subplots_adjust(wspace=0.5,hspace=1)#也可以调节各图形之间的间距
fig.tight_layout()#自动调整各图形之间的间距
plt.show()

    综上所述,对于乘客的获救情况,我们大致可以得出以下结论:

1.高等仓获救的机会大于低等舱

2.女性获救的机会大于男性

3.获救的几率与年龄有关

4.高等仓的平均年龄大于低等舱

2.数据预处理

    通过第一步的info函数查看数据的缺失情况,发现Age(年龄)缺失的数据较少,所以采用插值法来处理。用到的插值方法是随机森林。而Cabin(船舱号)则缺失了约3/4,而船舱号码暂时看不出来对获救有什么影响,所以我选择了对其进行数值化,有船舱号的值记为为1,没有船舱号的记为0。同样,为了方便后面的建模,我需要对非数值的属性Sex(性别),Embarked(登舱口),Name(名字),Ticket(票号)进行同样的数值化处理。这里用到了pandas库中的dummies函数。

from sklearn.ensemble import RandomForestRegressor
import numpy as np
import pandas as pd
from sklearn import preprocessing
data_train=pd.read_csv("D:/Titanic/data/train.csv")
# 使用 RandomForestClassifier 填补缺失的年龄属性
def set_missing_ages(df):
    age_df=df[['Age','Fare','Parch','SibSp','Pclass']]
    known_age=age_df[age_df.Age.notnull()].as_matrix()
    unknown_age=age_df[age_df.Age.isnull()].as_matrix()
    y=known_age[:,0]#第一列所有元素
    x=known_age[:,1:]#分割出矩阵第二列以后的所有元素
    rfr=RandomForestRegressor(random_state=0,n_estimators=2000,n_jobs=-1)
    rfr.fit(x,y)
    predictedAges=rfr.predict(unknown_age[:,1:])
    df.loc[(df.Age.isnull()),'Age']=predictedAges#loc通过行标签来索引数据
    return df

def set_Cabin_type(df):
    df.loc[ (df.Cabin.notnull()), 'Cabin' ] = "Yes"
    df.loc[ (df.Cabin.isnull()), 'Cabin' ] = "No"
    return df
data_train = set_missing_ages(data_train)
data_train = set_Cabin_type(data_train)
data_train.to_csv('processed_data1.csv')#新文件夹没有空值
dummies_Cabin=pd.get_dummies(data_train['Cabin'],prefix='Cabin')
dummies_Embarked=pd.get_dummies(data_train['Embarked'],prefix='Embarked')
dummies_Sex = pd.get_dummies(data_train['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(data_train['Pclass'], prefix= 'Pclass')
df = pd.concat([data_train, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)#增加列属性,concat默认是增加行,axis=1为增加列
df.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)#drop为删除原来的列,axis=1为删除列
df.to_csv('processed_data2.csv')#新文件夹的数据都为数值型,对原数据进行了特征因子化

处理后的数据如下:


此时数据都为数值型,但一些值的变化范围太大,如Fare,Age等,需要对其进行规范化处理,我采用的是零—均值规范化。

#将Age和Fare两个属性进行零——均值标准化。
scale_age=(df['Age']-df['Age'].mean())/df['Age'].std()
scale_fare=(df['Fare']-df['Fare'].mean())/df['Fare'].std()
df.copy()
df['Age']=scale_age
df['Fare']=scale_fare
df.to_csv('processed_data3.csv')

输出的文件部分如下图所示:


3.构建逻辑回归模型并进行预测

由于测试集的数据也是有缺失的,所以我先对测试集进行了和训练集同样的数据清洗工作,然后才开始了建模。

from sklearn import linear_model
import numpy as np
from sklearn.ensemble import RandomForestRegressor
import pandas as pd
from sklearn import preprocessing
from datapreprocessing import set_Cabin_type
df=pd.read_csv("D:/Titanic/processed_data3.csv")

train_df = df.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
train_np = train_df.as_matrix()
# y即Survival结果
y = train_np[:, 0]

# X即特征属性值
X = train_np[:, 1:]

# fit到LogisticRegression之中
clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
clf.fit(X, y)


####对测试数据同样进行数据预处理
data_test = pd.read_csv("D:/Titanic/data/test.csv")
data_train=pd.read_csv("D:/Titanic/data/train.csv")
#构建同一个随机森林
age_df=data_train[['Age','Fare','Parch','SibSp','Pclass']]
known_age=age_df[age_df.Age.notnull()].as_matrix()
unknown_age=age_df[age_df.Age.isnull()].as_matrix()
y=known_age[:,0]#第一列所有元素
x=known_age[:,1:]#分割出矩阵第二列以后的所有元素
rfr=RandomForestRegressor(random_state=0,n_estimators=2000,n_jobs=-1)
rfr.fit(x,y)
data_test.loc[ (data_test.Fare.isnull()), 'Fare' ] = 0
tmp_df = data_test[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
null_age = tmp_df[data_test.Age.isnull()].as_matrix()
X = null_age[:, 1:]
predictedAges = rfr.predict(X)
data_test.loc[ (data_test.Age.isnull()), 'Age' ] = predictedAges
data_test = set_Cabin_type(data_test)
dummies_Cabin = pd.get_dummies(data_test['Cabin'], prefix= 'Cabin')
dummies_Embarked = pd.get_dummies(data_test['Embarked'], prefix= 'Embarked')
dummies_Sex = pd.get_dummies(data_test['Sex'], prefix= 'Sex')
dummies_Pclass = pd.get_dummies(data_test['Pclass'], prefix= 'Pclass')
df_test = pd.concat([data_test, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
df_test.drop(['Pclass', 'Name', 'Sex', 'Ticket', 'Cabin', 'Embarked'], axis=1, inplace=True)
data_test.to_csv('processed_test_data1.csv')#新文件夹没有空值

#将Age和Fare两个属性进行零——均值标准化。
scale_age=(df['Age']-df['Age'].mean())/df['Age'].std()
scale_fare=(df['Fare']-df['Fare'].mean())/df['Fare'].std()
df.copy()
df['Age']=scale_age
df['Fare']=scale_fare
df.to_csv('processed_test_data2.csv')

#用逻辑回归模型做预测
test = df_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
predictions = clf.predict(test)
result = pd.DataFrame({'PassengerId':data_test['PassengerId'].as_matrix(), 'Survived':predictions.astype(np.int32)})
result.to_csv("logistic_regression_predictions.csv", index=False)

预测的结果部分如下:


    最后就是在kaggle上提交自己的结果,我的评分为0.76076。


做预测时我只是简单的构建了一个逻辑回归模型,没有对其进行优化。随着进一步的学习,有能力的话会对其进行检验并优化。

原文出处

3人推荐
随时随地看视频
慕课网APP