Titanic分析&预测(一)

IDE: Pycharm + Python 3
目标:根据已有数据集中的年龄、性别等属性和存活与否,建立回归模型,并利用测试集提供的数据,进行存活预测。本次实验采用Logistic Regression

需要引用的包

#encoding=utf-8

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sklearn.preprocessing as preprocessing
import sklearn.linear_model as linear_model
from sklearn.ensemble import RandomForestRegressor

数据集的路径以及格式如下图所示
数据集路径以及格式

程序结构如下图所示
程序结构

首先加载数据集,了解数据集的属性和数据类型

#数据集加载
def load_data(data_src):
    data = pd.read_csv(data_src)
    return data
#加载数据集
datatrain_src = 'D:\Dataset\Titanic\\Titanic_train.csv'
data_train = load_data(datatrain_src)
data_train .info()

数据集属性如下所示:
数据集属性

可以看出数据集一共有十二个属性,包括:

⚪ 两个浮点型 Age(年龄)、Fare(费用)
⚪ 五个整型数据 PassengerId(乘客编号)、Survived(是否存活)、Pclass(乘客类型)、SibSp(亲戚数量)、Parch(家属数量)
⚪ 五个Object型数据 Name(姓名)、Sex(性别)、Ticket(船票)、Cabin(舱位)、Embarked(港口)

部分属性有缺失值,稍后会做处理,先来查看各个属性的分布:

相关的属性分布

可以看出Survived人数、各个Pclass乘客人数的柱状图,各个Pclass中乘客年龄的密度分布,以及Embarked的柱状图。

代码如下所示:

#属性展示
def plot_attribute(data):
    fig = plt.figure('plot_attribute')
    fig.set(alpha=0.2)
    # 中文字体设置,PY3开始默认是unicode编码,中文不能正常显示
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False

    #存活数量柱状图
    plt.subplot(3, 2, 1)
    data.Survived.value_counts().plot(kind='bar')
    plt.title('Survived')
    plt.ylabel('count')

    #乘客类型数量柱状图
    plt.subplot(3, 2, 2)
    data.Pclass.value_counts().plot(kind="bar")
    plt.ylabel('count')
    plt.title('Pclass')

    #不同乘客类型的年龄分布密度图
    plt.subplot(3, 2, (3, 4))
    data.Age[data.Pclass == 1].plot(kind='kde')
    data.Age[data.Pclass == 2].plot(kind='kde')
    data.Age[data.Pclass == 3].plot(kind='kde')
    plt.xlabel('age')
    plt.ylabel('density')
    plt.title('Density of age in different Pclass')
    plt.legend(('A', 'B', 'C'), loc='best')

    #年龄分布散点图
    plt.subplot(3, 2, 5)
    plt.scatter(data.Survived, data.Age)
    plt.ylabel('age')
    # plt.grid(b=True, which='major', axis='y')
    plt.title('Age & Survived')

    #港口数量柱状图
    plt.subplot(3, 2, 6)
    data.Embarked.value_counts().plot(kind='bar')
    plt.title('Embarked & Survived')
    plt.ylabel('count')
    plt.show()
plot_attribute(data_train)

接下来查看属性和预测目标的关联分析,即不同的属性和存活与否的关系

⚪可以看出1类别的乘客存活几率最大,3类别乘客存活几率最小
乘客等级和存活关系

⚪可以看出女性存活的几率显著高于男性
性别和存活关系

⚪看得出S港口的人最多,Q港口的人最少
港口和存活关系

⚪有舱位的人存活概率较大
舱位和存活关系

代码如下:

#属性统计展示
def plot_attribute_static(data):
    fig = plt.figure('plot_attribute_static')
    fig.set(alpha=0.2)

    #乘客等级和存活关系
    Survived_0 = data.Pclass[data.Survived == 0].value_counts()
    Survived_1 = data.Pclass[data.Survived == 1].value_counts()
    df = pd.DataFrame({'Survived': Survived_1, 'Unsurvived': Survived_0})
    df.plot(kind='bar', stacked=True)
    plt.title('Pclass & Survived')
    plt.xlabel('Pclass')
    plt.ylabel('count')

    #性别和存活关系
    Survived_m = data.Survived[data.Sex == 'male'].value_counts()
    Survived_f = data.Survived[data.Sex == 'female'].value_counts()
    df = pd.DataFrame({'Male': Survived_m, 'Female': Survived_f})
    df.plot(kind='bar', stacked=True)
    plt.title('Sex & Survived')
    plt.xlabel('Sex')
    plt.ylabel('count')

    #港口和存活关系
    Survived_0 = data.Embarked[data.Survived == 0].value_counts()
    Survived_1 = data.Embarked[data.Survived == 1].value_counts()
    df = pd.DataFrame({'Survived': Survived_1, 'Unsurvived': Survived_0})
    df.plot(kind='bar', stacked=True)
    plt.title('Embarked & Survived')
    plt.xlabel('Embarked')
    plt.ylabel('count')

    #舱位和存活关系
    Survived_cabin = data.Survived[pd.notnull(data.Cabin)].value_counts()
    Survived_nocabin = data.Survived[pd.isnull(data.Cabin)].value_counts()
    df = pd.DataFrame({'Exist': Survived_cabin, u'Unexist': Survived_nocabin}).transpose()
    df.plot(kind='bar', stacked=True)
    plt.title('Cabin & Survived')
    plt.xlabel('Cabin')
    plt.ylabel('count')

    plt.show()

看完以上的关联属性之后,初步确定了建立模型所需要的属性:Pclass、Age、Sex、Fare、SibSp、Parch、Cabin、Embarked
Logistic Regression模型所需要的属性类型需要是整型数据,这里需要对以上属性做数据处理:

⚪缺失值处理
a.直接丢弃。但是数据来之不易,有它的存在价值,不能轻易否认。
b.填充。简单的有用中位数、平均数、众数等直接填充。常用的有回归拟合,用已知属性值拟合出缺失值,但是不合理的填充会产生噪声。

本文采用Random Forest来进行拟合。Random Forest会在数据集中进行采样建立多棵子树,再进行平均取值,能够更加真实的拟合出缺失值,实现结果如下图所示。

填充之前
缺失值处理之前

填充之后
缺失值处理之后

代码如下

#缺失值处理
def set_missing_ages(df):
    age_df = df[['Age', 'Fare', 'Parch', 'SibSp', 'Pclass']]

    # 乘客分成已知年龄和未知年龄两部分
    known_age = age_df[age_df.Age.notnull()].as_matrix()    #type为numpy.ndarray
    unknown_age = age_df[age_df.Age.isnull()].as_matrix()   #type为numpy.ndarray
    y = known_age[:, 0]
    X = known_age[:, 1:]
    #X[:, 0] = np.array(X[:, 0], dtype=np.float64)
    #print(X[:, 0].dtype)

    # fit到RandomForestRegressor之中
    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
    return df, rfr
data_train, rfr = set_missing_ages(data_train)
print(data_train.Age)

⚪特征处理。
对一些不宜拟合的数据做处理,如Cabin属性缺失值太多,因此将Yes和No作为Cabin属性新的值。处理如下

处理之前
处理之前

处理之后
处理之后

代码如下

#特征处理
def set_Cabin_type(df):
    df.loc[(df.Cabin.notnull()), 'Cabin'] = "Yes"
    df.loc[(df.Cabin.isnull()), 'Cabin'] = "No"
    return df
data_train = set_Cabin_type(data_train)
print(data_train.Cabin)

⚪特征因子化。
属性取值不是整型数据时,不能像比较数字10、100、1000一样来描述其大小作用,即不可量化处理的取值。为了能体现出属性下各个取值的“大小作用”,引入哑变量(Dummy Variable),将一个属性拆成k个属性,k就是原属性中不可量化的取值种类数目。如本例中Pclass属性,虽然是整型取值但不是用作大小比较的,因此将其拆分成三个新的属性Pclass_1(1=1/0=非1)、Pclass_2(1=2/0=非2)、Pclass_3(1=3/0=非3),这样就将Pclass的一维属性值在二维进行展开,同时没有丢失原属性值存储的信息。下面只将处理前后的前五条数据作展示:

处理前后对比

代码如下:

#特征因子化
def feature_factorization(data):
    dummies_Cabin = pd.get_dummies(data['Cabin'], prefix='Cabin')
    dummies_Embarked = pd.get_dummies(data['Embarked'], prefix='Embarked')
    dummies_Sex = pd.get_dummies(data['Sex'], prefix='Sex')
    dummies_Pclass = pd.get_dummies(data['Pclass'], prefix='Pclass')
    df = pd.concat([data, dummies_Cabin, dummies_Embarked, dummies_Sex, dummies_Pclass], axis=1)
    return df
data_train = feature_factorization(data_train)

⚪范围缩放
属性取值范围可能变化很大,不同属性的取值范围变化也很大,如本例中的Age和Fare属性。因此统一将所有属性缩放到合理的大小,以使模型训练保证准确度的前提下更加迅速。下面只将处理前后的前五条数据作展示:
处理前后

代码如下:

#特征归一化
def feature_standared(data):
    scaler = preprocessing.StandardScaler()
    age_scale_param = scaler.fit(data['Age'].values.reshape(-1, 1))
    data['Age_scaled'] = scaler.fit_transform(data['Age'].values.reshape(-1, 1), age_scale_param)
    fare_scale_param = scaler.fit(data['Fare'].values.reshape(-1, 1))
    data['Fare_scaled'] = scaler.fit_transform(data['Fare'].values.reshape(-1, 1), fare_scale_param)
    return data
data_train = feature_standared(data_train)

至此,数据处理部分已经完成,接下来就需要利用处理好的属性进行模型训练。

模型训练结果

#模型训练
def model_train(data):
    train_df = data.filter(regex='Survived|Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
    train_np = train_df.as_matrix()
    y = train_np[:, 0]
    X = train_np[:, 1:]
    clf = linear_model.LogisticRegression(C=1.0, penalty='l1', tol=1e-6)
    clf.fit(X, y)
    return clf
clf = model_train(data_train)

模型已经训练完成,将测试集作同样的数据处理,放入模型中即可输出预测结果,如下图所示:
训练结果前十条
代码如下:

#利用模型进行预测
test = data_test.filter(regex='Age_.*|SibSp|Parch|Fare_.*|Cabin_.*|Embarked_.*|Sex_.*|Pclass_.*')
prediction = clf.predict(test)
result = pd.DataFrame({'PassengerId': data_test['PassengerId'].as_matrix(),
                       'Survived': prediction.astype(np.int32)})
print(result.head(10))

这篇文章就到这里结束,这只是一个base_model,下一篇再介绍如何评估模型并进行优化。

猜你喜欢

转载自blog.csdn.net/sinat_34391940/article/details/82185235