kaggle—first play—Titanic

 

 

玩了很久总算是又静下心来好好看书,经过一段时间的学习,打算稍微检验一下知识的掌握程度,所以去kaggle参加了久闻的泰坦尼克生还预测,以下是正文。

-----------------------------------------------------------------------------------------

1、观察数据

拿到数据集后,先来了解数据的大致情况。

data.info()
data_des = data.describe() 

        

可以得知数据集有12列,891行,其中'Age'、'Cabin'、'Embarked'列存在缺失值,所有样本的平均生还率未0.383838;2等3等舱的人数比1等舱多;平均年龄为29.6991岁等等。

同时明确了需要预测的结果,即'Survived'的预测,是个明显的二分类问题,优先考虑逻辑回归、决策树、神经网络等算法。

以下为各列的含义:

passengerid_乘客ID    survived_是否获救(目标)    pclass_乘客等级
name_姓名    sex_性别    age_年龄(缺失)   sibsp_堂兄弟/妹个数    parch_父母/小孩个数   
ticket_船票信息    fare_票价    cabin_客舱号(缺失)    embarked_登船港口(缺失)

对数据分组对比,先观察乘客等级、年龄、性别、登船港口与是否生还的关系:

#性别生还率:女性生还率74.2%,男性生还率18.9%
sex_survived = data.groupby(by=['Sex'])['Survived'].agg({'总人数':np.size, '生还人数':np.sum})
sex_survived['未生还人数'] = sex_survived['总人数'] - sex_survived['生还人数']
sex_survived['生还率'] = sex_survived['生还人数'] / sex_survived['总人数']
#乘客等级生还率:1级乘客生还率最高
pclass_survived = data.groupby(by=['Pclass'])['Survived'].agg({'总人数':np.size, '生还人数':np.sum})
pclass_survived['未生还人数'] = pclass_survived['总人数'] - pclass_survived['生还人数']
pclass_survived['生还率'] = pclass_survived['生还人数'] / pclass_survived['总人数']
#各年龄段生还率:0-10岁生还率最高,60岁以上生还率最低
bins = [0,10,20,30,40,50,60,70,80]
data['age_cut'] = pd.cut(data['Age'],bins,right=False)
age_survived = data.groupby(by=['age_cut'])['Survived'].agg({'总人数':np.size, '生还人数':np.sum})
age_survived['未生还人数'] = age_survived['总人数'] - age_survived['生还人数']
age_survived['生还率'] = age_survived['生还人数'] / age_survived['总人数']
#各登船港口生还率:C港生还率最高,S港人数最多、生还率最低
embarked_survived = data.groupby(by=['Embarked'])['Survived'].agg({'总人数':np.size, '生还人数':np.sum})
embarked_survived['未生还人数'] = embarked_survived['总人数'] - embarked_survived['生还人数']
embarked_survived['生还率'] = embarked_survived['生还人数'] / embarked_survived['总人数']

###可视化
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] =False

plt.subplot(221)  #将图形区域分成2行*2列,将图形设置在第1个位置
plt.bar(sex_survived.index, sex_survived['生还人数'], color='b', alpha=0.7)
plt.bar(sex_survived.index, sex_survived['未生还人数'], bottom=sex_survived['生还人数'], color='lightblue')
plt.title('性别获救情况')
plt.ylabel('人数') 
plt.grid(b=True, which='major', axis='y')

plt.subplot(222)
plt.bar(pclass_survived.index, pclass_survived['生还人数'], color='b', alpha=0.7)
plt.bar(pclass_survived.index, pclass_survived['未生还人数'], bottom=pclass_survived['生还人数'], color='lightblue')
plt.xticks(pclass_survived.index)
plt.title('乘客等级获救情况')
plt.xlabel('乘客等级')
plt.ylabel('人数')
plt.grid(b=True, which='major', axis='y')

plt.subplot(223)
age_survived['age_index'] = age_survived.index.astype(str)
plt.bar(age_survived['age_index'], age_survived['生还人数'], color='b', alpha=0.7)
plt.bar(age_survived['age_index'], age_survived['未生还人数'], bottom=age_survived['生还人数'], color='lightblue')
plt.xticks(age_survived['age_index'])
plt.title('按年龄获救情况')
plt.xlabel('年龄分布')
plt.ylabel('人数')                   
plt.grid(b=True, which='major', axis='y')

使用循环优化代码后:

#各个维度的生还率
bins = [0,10,20,30,40,50,60,70,80]
data['age_cut'] = pd.cut(data['Age'],bins,right=False)
dataframe = ['sex_survived', 'pclass_survived', 'age_survived' , 'embarked_survived']
columns = ['Sex', 'Pclass', 'age_cut', 'Embarked']

for name in dataframe:
    for i in range(0,4):
        dataframe[i] = data.groupby(by=[columns[i]])['Survived'].agg({'总人数':np.size, '生还人数':np.sum})
        dataframe[i]['未生还人数'] = dataframe[i]['总人数'] - dataframe[i]['生还人数']
        dataframe[i]['生还率'] = dataframe[i]['生还人数'] / dataframe[i]['总人数']
print(dataframe)
  
#画图
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] =False
dataframe[2]['age_index'] = dataframe[2].index.astype(str) 
dataframe[2] = dataframe[2].set_index(dataframe[2]['age_index'])

for j in range(0,4):
    plt.subplot(2,2,j+1)  #将图形区域分成2行*2列,将图形设置在第1个位置
    plt.bar(dataframe[j].index, dataframe[j]['生还人数'], color='b', alpha=0.7)
    plt.bar(dataframe[j].index, dataframe[j]['未生还人数'], bottom=dataframe[j]['生还人数'], color='lightblue')
    plt.title(columns[j])
    plt.ylabel('人数') 
    plt.grid(b=True, which='major', axis='y')

得到如下的图形:(宝蓝色为获救)

数据显示:女性生还率74.2%,男性生还率18.9%;1级乘客生还率最高;0-10岁生还率最高,60岁以上生还率最低;C港生还率最高,S港人数最多、生还率最低

得到结论:性别、年龄、乘客等级、登船港口都对是否获救有较大影响。

另:船票价格与乘客等级相关较强,但与生还率的关系不明显;堂兄弟、父母/小孩数量对生还结果没有明显影响。

 

2、数据处理

 1)年龄的缺失项

由于年龄对于是否生还的影响还是比较明显,且缺失较多(缺失177个,接近20%),所以不能直接忽略缺失项或对缺失项做简单的均值、中位数等替换。

这里考虑使用随机森林对年龄进行预测填补:

https://scikit-learn.org/dev/modules/generated/sklearn.ensemble.RandomForestRegressor.html(随机森林官方文档)

#对年龄缺失项做随机森林进行填补
age_data = data[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
fcolumns = ['Fare', 'Parch', 'SibSp', 'Pclass']
tcolumns = ['Age']

age_data_known = age_data[age_data.Age.notnull()]
age_data_unknown = age_data[age_data.Age.isnull()]

fdata = age_data_known[fcolumns]#特征变量
tdata = age_data_known[tcolumns]#目标变量

from sklearn.ensemble import RandomForestRegressor
rfrmodel = RandomForestRegressor(n_jobs=-1)
rfrmodel.fit(fdata, tdata )

predictedAges = rfrmodel.predict(age_data_unknown[fcolumns])
data.loc[data['Age'].isnull(), 'Age'] = predictedAges

#对登船港口的2个缺失项用众数进行填补
data.loc[data['Embarked'].isnull(), 'Embarked'] = 'S'

2)非数值型特征的虚拟化

由于性别、登船港口还都是字符型数据,所以需要对这两个特征做虚拟变换

#设置训练集及虚拟变量
data_train = pd.DataFrame([])
data_train[['ID', 'age', 'pclass', 'sibsp', 'parch', 'fare', 'survived']] = data[['PassengerId', 'Age','Pclass','SibSp','Parch','Fare','Survived']]
#性别
data_train[['sex_female','sex_male']] = pd.get_dummies(data['Sex'])
#登船港口
data_train[['embarked_C','embarked_Q','embarked_S']] = pd.get_dummies(data['Embarked'])
data_train = data_train.set_index('ID')

3)数值特征标准化

由于年龄、船票价格两个特征跨度很大,所以对这两个特征做标准化处理

import sklearn.preprocessing as preprocessing
scaler = preprocessing.MinMaxScaler()
data_train['age'] = scaler.fit_transform(np.array(data_train['age']).reshape(891,-891))
data_train['fare'] = scaler.fit_transform(np.array(data_train['fare']).reshape(891,-891))

 

3、模型建立

首先使用逻辑回归模型

https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html(逻辑回归官方文档)

from sklearn import linear_model
lrModel = linear_model.LogisticRegression(penalty='l1')

inputcolumns = ['age', 'pclass', 'sibsp', 'parch', 'fare', 'sex_female',
       'sex_male', 'embarked_C', 'embarked_Q', 'embarked_S']
outpucolumns = ['survived']

lrModel.fit(data_train[inputcolumns], data_train[outpucolumns])
lrModel.score(data_train[inputcolumns], data_train[outpucolumns])#模型评分0.8

 

4、测试集处理

data2 = pd.read_csv(r'D:\kaggle\datafile\titanic\test.csv')
data2.info()#年龄缺失,船票价格存在一个缺失项
data2.loc[data2['Fare'].isnull(), 'Fare'] = data2['Fare'].mean()
#年龄缺失项处理
age_data2 = data2[['Age','Fare', 'Parch', 'SibSp', 'Pclass']]
age_data2_known = age_data2[age_data2.Age.notnull()]
age_data2_unknown = age_data2[age_data2.Age.isnull()]

fdata2 = age_data2_known[fcolumns]#特征变量
tdata2 = age_data2_known[tcolumns]#目标变量

rfrmodel.fit(fdata2, tdata2)
predictedAges2 = rfrmodel.predict(age_data2_unknown[fcolumns])
data2.loc[data2['Age'].isnull(), 'Age'] = predictedAges2
#构建训练集
data_test = pd.DataFrame([])
data_test[['ID', 'age', 'pclass', 'sibsp', 'parch', 'fare']] = data2[['PassengerId', 'Age','Pclass','SibSp','Parch','Fare']]
#虚拟变量
data_test[['sex_female','sex_male']] = pd.get_dummies(data2['Sex'])#性别
data_test[['embarked_C','embarked_Q','embarked_S']] = pd.get_dummies(data2['Embarked'])#登船港口
#数值标准化
data_test['age'] = scaler.fit_transform(np.array(data_test['age']).reshape(418,-418))
data_test['fare'] = scaler.fit_transform(np.array(data_test['fare']).reshape(418,-418))
#得到测试集预测结果
predictions = lrModel.predict(data_test[inputcolumns])
result = pd.DataFrame({'PassengerId':data_test['PassengerId'], 'Survived':predictions})

 如此就能够得到初步预测的结果了,后续会更新后面的优化等。

posted @ 2018-12-16 23:30  没有神保佑的瓶子  阅读(301)  评论(0编辑  收藏  举报