kaggle-titanic实战--数据挖掘实例

kaggle是一个国外的数据挖掘竞赛平台,大家做完竞赛之后会写一些指导,因此可以通过其他人写的指导文件进行学习,kaggle传送门

其中有一个入门类的分析问题是分析Titanic号的救援问题,分析哪些因素会影响到是否被救援,首先打开Titanic这个问题的具体页面,Titanic: Machine Learning from Disaster,

69961399.jpg

先看一看overview里面的description和evaluation,看看问题背景和最终需要预测的内容,然后点击数据,下载三个csv格式的数据集,第一个train.csv是训练集,第二个test.csv是测试集,第三个gender_submission.csv是验证集,

35388132.jpg

下载好之后打开pycharm,新建名为Titanic的工程,新建Titanic.py开始进行分析

首先,导入需要用到的包

import numpy as np
import pandas as pd
import matplot.pyplot as plt
from pandas import DataFrame,Series

接下来导入数据

train_data = pd.read_csv('train.csv')

查看数据的信息

train_data.info()

得到的数据信息如下

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
PassengerId    891 non-null int64
Survived       891 non-null int64
Pclass         891 non-null int64
Name           891 non-null object
Sex            891 non-null object
Age            714 non-null float64
SibSp          891 non-null int64
Parch          891 non-null int64
Ticket         891 non-null object
Fare           891 non-null float64
Cabin          204 non-null object
Embarked       889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.6+ KB

一共是891行,12列,其中Age列和Cabin列还有Embarked列数据不完整,每一列的含义如下:

  • PassengerId => 乘客ID
  • Pclass => 乘客等级(1/2/3等舱位)
  • Name => 乘客姓名
  • Sex => 性别
  • Age => 年龄
  • SibSp => 堂兄弟/妹个数
  • Parch => 父母与小孩个数
  • Ticket => 船票信息
  • Fare => 票价
  • Cabin => 客舱
  • Embarked => 登船港口

然后我们可以看看各个数据的统计值

train_data.describe()
PassengerIdSurvivedPclassAgeSibSpParchFare
count891891891714891891891
mean4460.3838382.30864229.699120.5230080.38159432.20421
std257.35380.4865920.83607114.52651.1027430.80605749.69343
min1010.42000
25%223.50220.125007.9104
50%44603280014.4542
75%668.513381031
max891138086512.3292

得到一个如图的描述,可以看到被救援的人数只有38%,且二,三等舱位人数居多,平均年龄29岁

这样得到的数据有一定的参考性,但是这么多个属性,究竟哪些和最终被救援有关系呢,我们可以画出图像来进行更加形象的描述

所有DataFrame类型的数据都可以在其后面直接调用plot函数,然后在其中输入kind来选择图的类型,绘制代码如下,

## 绘制被救情况
plt.subplot2grid((2,3),(0,0))## 画子图的第一个
fig1 = train_data.Survived.value_counts().plot(kind='bar')
plt.title('救援情况(1为被救)')
plt.ylabel('人数')
for patch in fig1.patches:
    fig1.annotate(str(int(patch.get_height())),(patch.get_x(),patch.get_height()))

## 绘制被救援和舱位之间的关系
ax2 = plt.subplot2grid((2,3),(0,1))
Survived_0 = train_data.Pclass[train_data.Survived == 0].value_counts()
Survived_1 = train_data.Pclass[train_data.Survived == 1].value_counts()
df=pd.DataFrame({ u'未获救':Survived_0, u'获救':Survived_1})
fig2 = df.plot(kind='bar', stacked=False , ax=ax2)
plt.title(u"各乘客等级的获救情况")
plt.xlabel(u"乘客等级")
plt.ylabel(u"人数")
## 用于标注直方图
for patch in fig2.patches:
    fig2.annotate(str(int(patch.get_height())),(patch.get_x(),patch.get_height()))

## 年龄与获救的关系
ax3 = plt.subplot2grid((2,3),(0,2))
plt.scatter(train_data.Survived, train_data.Age)
plt.title('获救与年龄的关系')
plt.ylabel('年龄')
# plt.xlim([0,1])
plt.xticks([0,1])

## 各等级舱位年龄分布
plt.subplot2grid((2,3),(1,0),colspan=2)
train_data.Age[train_data.Pclass == 1].plot(kind='kde')
train_data.Age[train_data.Pclass == 2].plot(kind='kde')
train_data.Age[train_data.Pclass == 3].plot(kind='kde')
plt.title('各等级舱位年龄分布')
plt.legend(['头等舱','二等舱','三等舱'])

## 各个口岸登船人数
plt.subplot2grid((2,3),(1,2))
train_data.Embarked.value_counts().plot(kind='bar')
plt.title('各个口岸登船人数')

plt.show()

绘制得到的图片如下:

98568081.jpg

其中标注直方图的代码为:

def Annotate(fig,plus_times=1.005):
    for patch in fig.patches:
        fig.text(patch.get_x()+patch.get_width()/2,patch.get_height()*plus_times,
                 str(int(patch.get_height())),ha='center',va='bottom')

接下来具体看看每个属性和是否被救援的关系

首先画出被救援和性别之间的关系

survived_m = train_data.Survived[train_data.Sex == 'male'].value_counts()
survived_f = train_data.Survived[train_data.Sex == 'female'].value_counts()
df_sex =  DataFrame(data={'男性':survived_m,'女性':survived_f})
df_sex.plot(kind='bar')
plt.title('被救援和性别的关系',fontsize=20)
plt.ylabel('人数',fontsize=15)
## 将横坐标的值改成中文
plt.xticks(range(2),['未获救','获救'],fontsize=15,rotation=360)
plt.legend(['男性','女性'],fontsize=15)
plt.show()

其中的字体大小设置可以用ctrl+B跳到原始代码中去看,大多数情况都是直接设置fontsize

4950204.jpg

舱位级别和性别对获救的影响

fig = plt.figure()
plt.suptitle('舱位级别和性别对获救的影响',fontsize=20)

#用于标注和设置横坐标的xticklables
def Annotate(fig,plus_times=1.005):
    for patch in fig.patches:
        fig.text(patch.get_x()+patch.get_width()/2,patch.get_height()*plus_times,
                 str(int(patch.get_height())),ha='center',va='bottom')
    fig.set_xticklabels(['未获救','获救'],rotation=0)
    
# 第一幅图
ax1 = fig.add_subplot(1,4,1)
a = train_data.Survived[train_data.Sex == 'female'][train_data.Pclass == 1].sort_values()
# train_data.Survived[train_data.Sex == 'female'][train_data.Pclass == 1].value_counts().plot(kind='bar',color='pink')
unsurvived = len(train_data.Survived[train_data.Survived==0][train_data.Sex == 'female'][train_data.Pclass == 1])
survived = len(train_data.Survived[train_data.Sex == 'female'][train_data.Pclass == 1][train_data.Survived==1])
ax1.bar(range(0,2),[unsurvived,survived],width=0.3,color='pink')
ax1.set_title('高级舱女性获救情况')
plt.xticks([0,1])
Annotate(ax1)

# 第二幅图
ax2 = fig.add_subplot(1,4,2)
train_data.Survived[train_data.Sex == 'female'][train_data.Pclass == 3].value_counts().plot(kind='bar',color='green')
Annotate(ax2)
ax2.set_title('低级舱女性获救情况')

# 第三幅图
ax1 = fig.add_subplot(1,4,3)
train_data.Survived[train_data.Sex == 'male'][train_data.Pclass == 1].value_counts().plot(kind='bar',color=['blue','yellow'])
ax1.set_title('高级舱男性性获救情况')
Annotate(ax1)

# 第四幅图
ax1 = fig.add_subplot(1,4,4)
train_data.Survived[train_data.Sex == 'male'][train_data.Pclass == 3].value_counts().plot(kind='bar',color='grey')
ax1.set_title('低级舱男性性获救情况')
Annotate(ax1)
plt.show()

接下来画出登船港口与是否获救的关系:

def Annotate(fig,plus_times=1.005):
    for patch in fig.patches:
        fig.text(patch.get_x() + patch.get_width() / 2, patch.get_height() * plus_times,
                                   str(int(patch.get_height())),ha='center',va='bottom')
unsurvived_Embarked = train_data.Embarked[train_data.Survived == 0].value_counts()
survived_Embarked = train_data.Embarked[train_data.Survived == 1].value_counts()
ax = pd.DataFrame(data={'获救':survived_Embarked,'未获救':unsurvived_Embarked}).plot(kind='bar')
plt.legend(['获救','未获救'],fontsize=15)
plt.title('登船港口与是否获救的关系',fontsize=20)
plt.ylabel('人数',fontsize=15)
ax.set_xticklabels(['s','c','q'],rotation=0,fontsize=15)
Annotate(ax)
plt.show()

88248188.jpg

接下来画出堂兄弟姐妹对是否获救的影响:

# 堂兄弟/妹对是否获救的影响
g = train_data.groupby(['SibSp','Survived'])
a=g.count()['PassengerId']
colors = ['blue','green']
fig = plt.figure()
x = [2*i for i in range(int(len(a)/2))]
plt.bar(x,a.iloc[x].values,color='blue',label='未获救',width=0.3)
plt.bar(x,a.iloc[::2].values,color='blue',label='未获救',width=0.3)
plt.bar([i+0.4 for i in x],a.iloc[1::2].values,color='green',label='未获救',width=0.3)
plt.legend()
plt.show()
pass

pandas选取偶数行和奇数行分别为:df.iloc[::2], df.iloc[1::2]

要获得Mutiindex的值只需要:df.index.values

下面看看cabin这个参数,这个参数的缺失很多,并且值的种类实在是太多了,基本是每个值都不同,我们要把这个参数作为一个特征的话,也许可以试试cabin是否缺失作为特征

survived_cabin = train_data.Survived[pd.notnull(train_data.Cabin)].value_counts()
survived_nocabin = train_data.Survived[pd.isnull(train_data.Cabin)].value_counts()
df = DataFrame(data={'有':survived_cabin, '没有':survived_nocabin}).T
ax = df.plot(kind='bar')
print(df)
# plt.xticks([0,1],['未获救','获救'])
plt.show()

70177085.jpg

看来有cabin这个参数更容易获救

因此我们需要将Cabin的有无转化为bool型变量:

# 将cabin的有无转化为bool型变量
def bool_Cabin(df):
    df.loc[pd.notnull(df.Cabin), 'Cabin']= 'Yes'
    df.loc[pd.isnull(df.Cabin), 'Cabin']= 'No'
    return df

使用RandomForest Regression 对年龄数据进行拟合

因为年龄数据差的比较多,所以我们想到要将年龄数据进行补全,所以想到了拟合年龄的曲线,在这里我们使用的方法是RandomForestRegressor

from sklearn.ensemble import RandomForestRegressor
def matchAge(df):
    # 通过已知的数值型变量来拟合Age这个参数
    age_df = df[['Age','Pclass','SibSp','Parch','Fare']]
    
    #通过pd.notnull和pd.isnull来判断是否有年龄这个值,并转化为as_matrix()
    knowAge = age_df[pd.notnull(age_df.Age)].as_matrix()
    unknowAge = age_df[pd.isnull(age_df.Age)].as_matrix()
    
    # 建立label,即为需要预测的标签的已知值,即训练时用到的标签
    lable = knowAge[:,0]
    # 建立x,即输入的训练样本
    x = knowAge[:,1:]
    
  # 初始化随机森林回归的参数,n_estimators=2000表示迭代2000次,n_jobs=-1表示用cpu的所有核进行并行计算
    rfc = RandomForestRegressor(random_state=0, n_estimators=2000, n_jobs=-1)
   # 开始训练
    rfc.fit(x,lable)
   
  # 开始利用训练好的模型进行预测
    predictedAges = rfc.predict(unknowAge[:, 1:])
    
   # 将原始数据的空值部分赋值为预测的数据
    df.Age[pd.isnull(df.Age)] = predictedAges
    # 返回数据集
    return df,rfc

将非数字的值转化为数字

pandas提供了一个get_dummies函数,可以直接把可以分类的数据转换为多个成标量值,比如下面的将Cabin转化为了Cabin_yes 和Cabin_no:

dummies_Cabin = pd.get_dummies(train_data['Cabin'], prefix='Cabin')
dummies_Embarked = pd.get_dummies(train_data['Embarked'], prefix='Embarked')
dummies_Sex = pd.get_dummies(train_data['Sex'], prefix='Sex')
dummies_Pclass = pd.get_dummies(train_data['Pclass'], prefix='Pclass')

连接两个DataFrame

只要用pd.concat([df1,df2], axis=1),就可以按列连接

train_data = pd.concat([train_data,dummies_Cabin,dummies_Embarked,dummies_Sex,dummies_Pclass],axis=1)

删除某些列

直接df.drop(['column1','column2'], axis=1, inplace=True),就是按列删除,并且inplace=True表示将原来的df直接替换成删除掉某些列之后的数据

train_data.drop(['Name','Sex','Ticket','Cabin','Embarked'],axis=1, inplace=True)

数据归一化

使用sklearn.preprocessing包的preprocessing函数,先定义一个scaler实例,用preprocessingStandardScaler,用scaler先fit出你想要归一化的那一列的参数,然后用fit_transform进行归一化,传入的参数是需要归一化的值和归一化参数

#数据预处理
import sklearn.preprocessing as preprocessing

scaler = preprocessing.StandardScaler()
age_scale_param = scaler.fit(train_data[['Age']])
train_data['Age_scaled'] = scaler.fit_transform(train_data[['Age']],age_scale_param)
Fare_scale_param = scaler.fit(train_data[['Fare']])
train_data['Fare_scaled'] = scaler.fit_transform(train_data[['Fare']],Fare_scale_param)

逻辑回归预测

计算完这些部分,将测试数据导入并进行与训练数据相同的预处理,然后进行逻辑回归预测,先用train_data进行fit,然后用训练数据的x进行预测

from sklearn import linear_model

train_data = pd.read_csv('prepross_train.csv',index_col=0)
train_data.info()

train_df = train_data.iloc[:,1:].as_matrix()
y = train_df[:,0]
x = train_df[:,1:]
# test_data = prepross('test.csv','prepross_test.csv')
test_data = pd.read_csv('prepross_test.csv',index_col=0)

clf = linear_model.LogisticRegression(penalty='l1',C=1.0,tol=1e-6)
clf.fit(x, y)
test_x = test_data.iloc[:,1:]
prediction = clf.predict(test_x)

result = DataFrame(data={'PassengerId':test_data['PassengerId'].as_matrix(),'Survived':[int(i) for i in prediction]})
result.to_csv('result.csv')

检验预测精度

因为我们一开始在进行测试数据预处理的时候,删除了一行,所以在比较的时候应该把这一行补上,在补充完毕之后index是乱的,所以我们直接reset_index,并且sort_values,按照PassengerId排序

auth_df = pd.read_csv('gender_submission.csv')
result_df = pd.read_csv('result.csv',index_col=0)
s = 0

a = result_df['PassengerId'].values
b = auth_df['PassengerId'].values
c = [c for c in b if c not in a][0]
result_df = pd.concat([result_df,auth_df[auth_df.PassengerId == c]],axis=0)

result_df.reset_index(drop=True,inplace=True)
result_df.sort_values(by='PassengerId',inplace=True)
result_df.reset_index(drop=True,inplace=True)

result_df.loc[auth_df.PassengerId == c,'Survived'] = 1
for i,j in zip(result_df['Survived'].values, auth_df['Survived'].values):
    if i == j:
        s += 1
print(s)
precession = float(s/len(auth_df['Survived']))
print(precession)

精度得到为0.9330143540669856

转载于:https://www.cnblogs.com/drawon/p/8520620.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值