数据科学 VS 随机
一个比较经典问题:预测二元事件的结果。换句话说,就是它不是发生就是没有发生。 例如,你赢了或者没有赢,你通过了考试或者没有通过考试,你被接受或者不被接受等。 常见的业务场景就是用户流失或留存,另现实案例是医疗事件的死亡率或生存率分析。二元事件产生了一个有趣的现象,因为我们统计知道,随机猜测应该达到50%的准确率,而不需要创建一个单一的算法或编写一行代码。这篇文章,我使用机器学习入门经典例子Titanic:Machine Learning from Disaste(泰坦尼克号乘客生存预测)来实际操作,将对应的算法应用在给出的数据集上进行预测。
数据工作的基本流程
定义问题: 我们首先需要解决的是我们将面临一个什么问题,需要我们做什么,俗话说的磨刀不误砍柴工,首先看清对手是谁才能有的放矢。
收集数据: 根据确定的数据分析对象,抽象出在数据分析中所需要的特征信息,然后选择合适的信息收集方法,将收集到的信息存入数据库。对于海量数据,选择一个合适的数据存储和管理的数据仓库是至关重要的。
准备消费数据: 把不同来源、格式、特点性质的数据在逻辑上或物理上有机地集中,从而为企业提供全面的数据共享。如果执行多数的数据挖掘算法,即使是在少量数据上也需要很长的时间,而做商业运营数据挖掘时数据量往往非常大。数据规约技术可以用来得到数据集的规约表示,它小得多,但仍然接近于保持原数据的完整性,并且规约后执行数据挖掘结果与规约前执行结果相同或几乎相同。在数据库中的数据有一些是不完整的(有些感兴趣的属性缺少属性值)、含噪声的(包含错误的属性值),并且是不一致的(同样的信息不同的表示方式),因此需要进行数据清理,将完整、正确、一致的数据信息存入数据仓库中。不然,挖掘的结果会差强人意。通过平滑聚集、数据概化、规范化等方式将数据转换成适用于数据挖掘的形式。对于有些实数型数据,通过概念分层和数据的离散化来转换数据也是重要的一步。
探索性分析: 根据数据仓库中的数据信息,选择合适的分析工具,应用统计方法、事例推理、决策树、规则推理、模糊集,甚至神经网络、遗传算法的方法处理信息,得出有用的分析信息。
数据建模: 像描述性和推论性统计数据一样,数据建模可以总结数据或预测未来的结果。 您的数据集和预期结果将决定可供使用的算法。 重要的是要记住,算法是工具,而不是魔杖。 你仍然必须是知道如何为工作选择正确的工具的工匠。 一个比喻就是要求有人给你一把飞利浦剃须刀,他们给你一把螺丝刀或者一把锤子。 充其量,它显示完全缺乏了解。 最糟糕的是,这使得项目不可能完成。 数据建模也是如此。 错误的模型可能导致最差的表现,甚至会导致错误的结论。
模型验证和模型使用: 用训练数据对模型进行训练之后,就可以用于预测数据。
话不多说,下面我们正式进入正题。
第一步:问题描述
这个项目里,我们需要做的是设计一个算法来预测泰坦尼克号乘客的生存结果。
项目 概览:
泰坦尼克号的沉没是历史上最臭名昭着的海难事故之一。 1912年4月15日,在首航期间,泰坦尼克号撞上一座冰山后沉没,2224名乘客和机组人员中有1502人遇难。 这一耸人听闻的悲剧震撼了国际社会,并导致了更好的船舶安全条例。
沉船导致生命损失的原因之一是乘客和船员没有足够的救生艇。虽然幸存下来的运气有一些因素,但一些人比其他人更有可能生存,比如妇女,儿童和上层阶级。
在这个挑战中,我们要求你完成对什么样的人可能生存的分析。特别是,我们要求你运用机器学习的工具来预测哪些乘客在灾难中会幸存。
锻炼技能
二分类
Python 基础
第二步: 收集数据
数据集请到连接处下载 Titanic: Machine Learning from Disaster
第三步: 建模预测
这一步将对数据进行清洗、整理,处理空值等一系列操作。
3.1 系统环境
import sys
print("Python version: {}". format(sys.version))
import pandas as pd
print("pandas version: {}". format(pd.__version__))
import matplotlib
print("matplotlib version: {}". format(matplotlib.__version__))
import numpy as np
print("NumPy version: {}". format(np.__version__))
import scipy as sp
print("SciPy version: {}". format(sp.__version__))
import IPython
from IPython import display
print("IPython version: {}". format(IPython.__version__))
import sklearn
print("scikit-learn version: {}". format(sklearn.__version__))
import random
import time
import warnings
warnings.filterwarnings('ignore')
Python version: 2.7.10 (default, Oct 23 2015, 19:19:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)]
pandas version: 0.21.1
matplotlib version: 2.1.1
NumPy version: 1.13.3
SciPy version: 1.0.0
IPython version: 5.5.0
scikit-learn version: 0.19.1
3.11 加载机器学习库
这里主要使用python的scikit-learn 数据机器学习库来进行建模以及matplotlib、seaborn图形库来进行可视化操作。
from sklearn import svm, tree, linear_model, neighbors, naive_bayes, ensemble, discriminant_analysis, gaussian_process
from xgboost import XGBClassifier
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
from sklearn import feature_selection
from sklearn import model_selection
from sklearn import metrics
#可视化
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.pylab as pylab
import seaborn as sns
from pandas.tools.plotting import scatter_matrix
%matplotlib inline
mpl.style.use('ggplot')
sns.set_style('white')
pylab.rcParams['figure.figsize'] = 12,8
3.2 数据观察
这是我们面向数据的第一步,在做进行数据建模分析之前,我们首先得观察数据长什么样,具有什么样的特点,对拿到手的数据我们的目标是要做什么等进行初步认识,我们先导入数据进行观察。
data_raw = pd.read_csv('./Titanic/input/train.csv')
data_val = pd.read_csv('./Titanic/input/test.csv')
data1 = data_raw.copy(deep = True)
data_cleaner = [data1, data_val]
print (data_raw.info())
data_raw.sample(10)
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
01EA59FD892CB4FD8FE16BFC0C4A4B78.jpg
3.3 数据修正、空值处理、新建特征、数据转换
这一步我们需要进行上述四步大致操作,需要这样做的原因分别为:
** 修正清洗**:从上面的原始数据统计信息里可以看到,其中有很多错误或者不合理的数据,比如Age、Cabin那两列就有很多缺失值,还有如果数据中有一些奇异值,比如有一个乘客个年龄特别大,可能为300多甚至更大,这样的数据存在就可能会给我们的模型造成干扰,我们选择去修复这样的一些数据,是因为我们会认为数据修复之后对我们模型的精确性带来一定的提升,然而事实也缺失会是这样。
空值处理: 在Cabin,Age 等字段,含有一些空值,这些数据可能是因为没法收集到乘客的某些信息导致,这些记录的处理方式通常比较直观的有两种方法,一个最简单的就是直接把含有空值的记录删掉,另外一个是按某种规则对缺失的值进行填充。第一种方法通常不是很推荐的,因为这样的话会损失很多训练数据,有时字段的缺失也在某种程度上提供了一定的信息,而且当训练数据中大量记录含有空值的情况下把这些记录删除会导致我们的训练数据不足而引发模型精度达不到预期的效果。如果是填充记录的话方法有很多,比较常见的有均值,中位数等填充方式。
新建特征: 我们可以利用现有的一些特征产生一些更多的特征。
数据转换:从原始数据上看,有很多字符类特征,通常我们在将数据输入模型的时候更希望是用数值型的特征,在上述数据集中我们将用分类标签来转换其中一些特征。
3.4 清理数据
for dataset in data_cleaner:
dataset['Age'].fillna(dataset['Age'].median(), inplace = True)
dataset['Embarked'].fillna(dataset['Embarked'].mode()[0], inplace = True)
dataset['Fare'].fillna(dataset['Fare'].median(), inplace = True)
drop_column = ['PassengerId','Cabin', 'Ticket']
data1.drop(drop_column, axis=1, inplace = True)
print(data1.isnull().sum())
print("-"*10)
print(data_val.isnull().sum())
Survived 0
Pclass 0
Name 0
Sex 0
Age 0
SibSp 0
Parch 0
Fare 0
Embarked 0
dtype: int64
PassengerId 0
Pclass 0
Name 0
Sex 0
Age 0
SibSp 0
Parch 0
Ticket 0
Fare 0
Cabin 327
Embarked 0
dtype: int64
#训练数据处理
for dataset in data_cleaner:
dataset['FamilySize'] = dataset ['SibSp'] + dataset['Parch'] + 1
dataset['IsAlone'] = 1
dataset['IsAlone'].loc[dataset['FamilySize'] > 1] = 0
dataset['Title'] = dataset['Name'].str.split(", ", expand=True)[1].str.split(".", expand=True)[0]
dataset['FareBin'] = pd.qcut(dataset['Fare'], 4)
dataset['AgeBin'] = pd.cut(dataset['Age'].astype(int), 5)
stat_min = 10
title_names = (data1['Title'].value_counts() < stat_min)
data1['Title'] = data1['Title'].apply(lambda x: 'Misc' if title_names.loc[x] == True else x)
print(data1['Title'].value_counts())
print("-"*10)
#再看一下我们的数据
data1.info()
data_val.info()
data1.sample(10)
3.5 格式转换
这里我们会把相关特征转换成类别标签,然后把分类数据转换拉成多列特征数据。
label = LabelEncoder()
for dataset in data_cleaner:
dataset['Sex_Code'] = label.fit_transform(dataset['Sex'])
dataset['Embarked_Code'] = label.fit_transform(dataset['Embarked'])
dataset['Title_Code'] = label.fit_transform(dataset['Title'])
dataset['AgeBin_Code'] = label.fit_transform(dataset['AgeBin'])
dataset['FareBin_Code'] = label.fit_transform(dataset['FareBin'])
Target = ['Survived']
data1_x = ['Sex','Pclass', 'Embarked', 'Title','SibSp', 'Parch', 'Age', 'Fare', 'FamilySize', 'IsAlone']
data1_x_calc = ['Sex_Code','Pclass', 'Embarked_Code', 'Title_Code','SibSp', 'Parch', 'Age', 'Fare']
data1_xy = Target + data1_x
#print('Original X Y: ', data1_xy, '\n')
data1_x_bin = ['Sex_Code','Pclass', 'Embarked_Code', 'Title_Code', 'FamilySize', 'AgeBin_Code', 'FareBin_Code']
data1_xy_bin = Target + data1_x_bin
#print('Bin X Y: ', data1_xy_bin, '\n')
data1_dummy = pd.get_dummies(data1[data1_x])
data1_x_dummy = data1_dummy.columns.tolist()
data1_xy_dummy = Target + data1_x_dummy
#print('Dummy X Y: ', data1_xy_dummy, '\n')
data1_dummy.head()
经过上述处理之后,我们的训练数据要比原始数据整齐规范了很多。
3.6 拆分训练数据和测试数据
为了防止我们的模型发生过拟合或者欠拟合之类问题(具体定义自行百度),我们需要将数据进行拆分,用一部分数据进行训练,然后用剩余的数据进行准确性验证,这种也是监督学习模型特有的,这里我们用sklearn 库里现有的函数进行拆分,通常训练集和测试集的划分比例为75/25
#split the data set
train1_x, test1_x, train1_y, test1_y = model_selection.train_test_split(data1[data1_x_calc], data1[Target], random_state = 0)
train1_x_bin, test1_x_bin, train1_y_bin, test1_y_bin = model_selection.train_test_split(data1[data1_x_bin], data1[Target] , random_state = 0)
train1_x_dummy, test1_x_dummy, train1_y_dummy, test1_y_dummy = model_selection.train_test_split(data1_dummy[data1_x_dummy], data1[Target], random_state = 0)
print("Data1 Shape: {}".format(data1.shape))
print("Train1 Shape: {}".format(train1_x.shape))
print("Test1 Shape: {}".format(test1_x.shape))
train1_x_bin.head()
Data1 Shape: (891, 19)
Train1 Shape: (668, 8)
Test1 Shape: (223, 8)
3.7 可视化数据进行统计观测
在我们把数据清理完成之后,我们可以通过可视化工具将我们的目标列和各特征属性的关系打印出来看看相互关系,这样以便我们对手中的数据有个更直观的感觉。
下面我们只举几个例子,其他的特征关系可以照例打印出来。
data1整理后的数据协方差矩阵热力图
3.7 建模分析
在经过上述步骤对模型数据进行处理之后,数据已经基本可用,同时通过可视化手段对数据进行预览对整体的分布有个大致把握,接下来的工作就是建立模型,这一步通常需要一些计算机、数学、商业分析等方面的知识,属于多学科的一个交叉,不过幸亏有很多现成的工具包已经帮我们封装好了很多算法,因此我们只需要几行代码甚至就能将模型建立出来。通常机器学习可大致分为:监督学习、非监督学习、强化学习,这里我们的问题将归结为监督学习问题。然而对于同一个数据,我们有很多算法模型可以选择,具体什么样的模型适合试验的数据,这个得根据用户的数据特征来决定,挑选模型的过程也是一个经验要求很高的步骤。这里我们挑出一些很常见的算法都训练一下然后比较预测的结果,详细的算法使用请参见对应的scikit-learn文档。
MLA = [
ensemble.AdaBoostClassifier(),
ensemble.BaggingClassifier(),
ensemble.ExtraTreesClassifier(),
ensemble.GradientBoostingClassifier(),
ensemble.RandomForestClassifier(),
gaussian_process.GaussianProcessClassifier(),
linear_model.LogisticRegressionCV(),
linear_model.PassiveAggressiveClassifier(),
linear_model.RidgeClassifierCV(),
linear_model.SGDClassifier(),
linear_model.Perceptron(),
#朴素贝叶斯
naive_bayes.BernoulliNB(),
naive_bayes.GaussianNB(),
neighbors.KNeighborsClassifier(),
#支持向量机
svm.SVC(probability=True),
svm.NuSVC(probability=True),
svm.LinearSVC(),
#决策树
tree.DecisionTreeClassifier(),
tree.ExtraTreeClassifier(),
discriminant_analysis.LinearDiscriminantAnalysis(),
discriminant_analysis.QuadraticDiscriminantAnalysis(),
XGBClassifier()
]
#训练集拆分
cv_split = model_selection.ShuffleSplit(n_splits = 10, test_size = .3, train_size = .6, random_state = 0 )
#创建对比结果集
MLA_columns = ['MLA Name', 'MLA Parameters','MLA Train Accuracy Mean', 'MLA Test Accuracy Mean', 'MLA Test Accuracy 3*STD' ,'MLA Time']
MLA_compare = pd.DataFrame(columns = MLA_columns)
MLA_predict = data1[Target]
row_index = 0
for alg in MLA:
#设置参数
MLA_name = alg.__class__.__name__
MLA_compare.loc[row_index, 'MLA Name'] = MLA_name
MLA_compare.loc[row_index, 'MLA Parameters'] = str(alg.get_params())
#交叉验证
cv_results = model_selection.cross_validate(alg, data1[data1_x_bin], data1[Target], cv = cv_split)
MLA_compare.loc[row_index, 'MLA Time'] = cv_results['fit_time'].mean()
MLA_compare.loc[row_index, 'MLA Train Accuracy Mean'] = cv_results['train_score'].mean()
MLA_compare.loc[row_index, 'MLA Test Accuracy Mean'] = cv_results['test_score'].mean()
MLA_compare.loc[row_index, 'MLA Test Accuracy 3*STD'] = cv_results['test_score'].std()*3
alg.fit(data1[data1_x_bin], data1[Target])
MLA_predict[MLA_name] = alg.predict(data1[data1_x_bin])
row_index+=1
MLA_compare.sort_values(by = ['MLA Test Accuracy Mean'], ascending = False, inplace = True)
MLA_compare
整体上看,XGBClassifier 的实际预测精度最高,而其中有几个算法模型在训练数据集上达到了0.895131的最高精度,但是在测试数据集合上的表现比XGBClassifier 分类器差了稍微一点点。
3.8 小结分析
经过初步的数据处理、分析,我们的模型将预测正确度从随机的0.5提高到了82%,这已经是一个非常大的进步了,然而我们可能会想,还有没有什么方法对我们的模型精度更进一步提高?这个答案是肯定的,不过这里咱们就暂时不介绍了,还没学到。。。嘻嘻。这就是最近学习的一些基本的机器学习方面相关的知识了,以后还得经常向大牛们学习!