机器学习项目实战(一): Kaggle Titanic


Kaggle Titanic(泰坦尼克号幸存预测)

做为第一次参加 Kaggle 竞赛,因此选择了一个入门级的“泰坦尼克号幸存预”。之前一直是看《机器学习实用指南》这本书,这个竞赛也是这本书中的一道课后题。本教程使用 Scikit-Learn 来进行,由于是我第一个机器学习项目,因此只适合于初学者,大神请留下珍贵的建议。

首先在开始之前得明确一下机器学习的简单步骤:

ml-map

接下来按照这个步骤来一步步的进行处理

一、提出问题

Titanic是 Kaggle 上的一个竞赛。属于入门级比赛,在 Kaggle 提供的数据集中,共有1309名乘客数据,其中891是已知存活情况,剩下418则是需要进行分析预测的。

这项竞赛属于机器学习中的二元分类问题,为了获取到分析所需的数据,首先需要去 Kaggle 首页去创建一个账号,然后加入到Titanic竞赛中,从 Data 中下载所需要的数据。

下载的数据包括:

  • gender_submission.csv:提交结果案例(提交结果)
  • test.csv:测试数据
  • train.csv:训练数据

二、理解数据

说到数据挖掘,是把散乱数据转换成「有价值」信息的过程,数据是可以是数字或者文本内容甚至图像,而信息是有语义的、人脑可理解的报告、图表。

数据分析的结果,就是把数字转化成人类可理解的信息。

先将所需的数据导入进来

train_set = pd.read_csv('./datasets/titanic/train.csv')
test_set = pd.read_csv('./datasets/titanic/test.csv')

接下来查看下数据:

train_set.head()

12

其中各列所代表的信息为:

  • PassengerId:乘客的ID(对预测没有用处)
  • survival:是否存活,0表示死亡,1表示存活
  • pclass:船票的类别,可以用来表示乘客的经济情况,1 = 1st, 2 = 2nd, 3 = 3rd
  • sex:乘客性别
  • Age:乘客年龄
  • sibsp:船上兄弟姐妹及配偶的个数
  • parch:船上父母或子女的个数
  • ticket:船票号
  • fare:船票价格
  • cabin:客舱号码
  • embarked:登船口岸,C = Cherbourg, Q = Queenstown, S = Southampton

查看数据的基本信息:

train_set.info()

可以看到,Age、Cabin、Embarked 这几个属性都具有缺失值,其中 Cabin 缺失的最严重,具有缺失值的都要在数据清洗中进行处理。

13

再来看一下训练集中数字类型特征的统计信息

train_set.describe()

14

对数据进行简单的预览来了解数据,这为我们下一步数据清洗指明了方向,只有知道哪些数据缺失数据,哪些数据存在问题,我们才能有针对性的处理。

三、数据清洗

数据清洗操作包括 数据预处理 以及 特征工程两个部分,数据清洗是机器学习中最重要最耗时的部分,经常需要多次反复的进行,这里可以使用 Scikit-learn 中提供的 pipeline 管道来同时进行这两部操作。

1.数据预处理

对于具有缺失值的特征数据来说,一般的处理方式包括 将缺失值填充 或者 删除具有缺失值的数据。这里我们使用填充的方式来处理具有缺失值的数据。

根据缺失的数据是数字还是非数字所对应的填充策略也不一样。

对于数字数据 Age、Fare 来说是使用其数据的中位数来进行填充。

而非数字数据包括:Embarked(港口数据)以及 Cabin(船舱号),港口数据只两个缺失值,我们将缺失值填充为最频繁出现的值:S=英国南安普顿 Southampton;而船舱号缺失数据比较多,我们不使用改特性来进行预测。

2.特征工程

特征工程是整个机器学习过程中最重要的阶段,数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。

我们需要通过探索数据,利用先验知识,从数据中总结出特征。

那特征工程到底是什么呢?顾名思义,其本质是一项工程活动,目的是最大限度地从原始数据中提取特征以供算法和模型使用。通过总结和归纳,人们认为特征工程包括以下方面:

15

特征处理是特征工程的核心部分,sklearn 提供了较为完整的特征处理方法,包括数据预处理,特征选择,降维等。

这里我们选择 “Age”, “SibSp”, “Parch”, “Fare”, “Pclass”, “Sex”, “Embarked” 这几个特性来进行预测。(这里选择的特征是书上选择的,一般来说可以通过查看特征与预测特征的依赖关系来选择)

首先编写一个类来将指定的特征从数据集中选择出来

from sklearn.base import BaseEstimator, TransformerMixin

# A class to select numerical or categorical columns 
# since Scikit-Learn doesn't handle DataFrames yet
class DataFrameSelector(BaseEstimator, TransformerMixin):
    def __init__(self, attribute_names):
        self.attribute_names = attribute_names
    def fit(self, X, y=None):
        return self
    def transform(self, X):
        return X[self.attribute_names]

首先将数字类型选择出来,并将其中有缺失值的部分进行填充,这里使用 Scikit-learn 中的管道

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import Imputer

# 按中位数进行填充
imputer = Imputer(strategy="median")

num_pipeline = Pipeline([
        ("select_numeric", DataFrameSelector(["Age", "SibSp", "Parch", "Fare"])),
        ("imputer", Imputer(strategy="median")),
    ])

来查看下管道的处理结果

num_pipeline.fit_transform(train_set)

16

接下来对非数字类型的特性进行数据清洗,首先对具有缺失数据的数据填充为其中出现最多的值,并将其表示为 OneHot 数字类型的格式。

class MostFrequentImputer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        self.most_frequent_ = pd.Series([X[c].value_counts().index[0] for c in X],
                                        index=X.columns)
        return self
    def transform(self, X, y=None):
        return X.fillna(self.most_frequent_)

from future_encoders import OneHotEncoder

cat_pipeline = Pipeline([
        ("select_cat", DataFrameSelector(["Pclass", "Sex", "Embarked"])),
        ("imputer", MostFrequentImputer()),
        ("cat_encoder", OneHotEncoder(sparse=False)),
    ])

查看下管道处理的结果

cat_pipeline.fit_transform(train_set)

17

四、构建模型

在构建模型之前先得获取到训练模型所需的训练数据,包括训练输入数据以及相对应的训练输出数据。

1.获取训练数据

将上述的管道操作组合为一个完整的管道处理

# 将数据的清洗操作做为一个完整的管道操作来进行
from sklearn.pipeline import FeatureUnion
preprocess_pipeline = FeatureUnion(transformer_list=[
        ("num_pipeline", num_pipeline),
        ("cat_pipeline", cat_pipeline),
    ])

来对测试数据进行上述的管道操作,得到最后的输入训练数据

X_train = preprocess_pipeline.fit_transform(train_set)
X_train

18

在来获取输出的训练数据

y_train = train_set['Survived'] == 1

2.构建模型

模型这里选择的是 RandomForestClassifier

from sklearn.ensemble import RandomForestClassifier

forest_clf = RandomForestClassifier(random_state=42)

forest_clf.fit(X_train,y_train)

五、模型评估

查看模型的准确性

forest_clf.score(X_train,y_train)

19

六、方案实施

接下来便使用我们创建的模型来对测试数据进行预测

# 对测试数据集进行相同的数据预处理管道操作
X_test = preprocess_pipeline.fit_transform(test_set)
# 使用模型对数据进行预测
y_test = forest_clf.predict(X_test)

# 乘客id
passenger_id = test_set['PassengerId']
# 预测结果转换为int类型
y_test = y_test.astype(int)

# 将结果做为新的数据保存
pred_df = pd.DataFrame( 
    { 'PassengerId': passenger_id , 
     'Survived': y_test } )
pred_df.shape

# 保存到本地
pred_df.to_csv("./datasets/titanic/prediction.csv", index=False)

将最后生成的结果提交到 Kaggle 上看一下自己的排名吧。

参考文章地址

  • https://zhuanlan.zhihu.com/p/33565306
  • https://zhuanlan.zhihu.com/p/27655949
  • http://www.cnblogs.com/jasonfreak/p/5448385.html