深圳达内IT培训
美国上市IT培训机构

13147027653

热门课程

零基础学习Python3从机器学习开始

  • 时间:2018-01-06
  • 发布:python
  • 来源:达内新闻

这篇文章适合任何会简单英语和基础电脑操作的任何人。这篇笔记从安装Python开始,用最通俗的语言向大家分享我的Python机器学习记录,主旨在帮助大家对如何用Python做Project有个基本的印象,所以大家再读的时候以理解分析思路为主,不需要太过纠结具体的代码。个人建议先无脑复制黏贴一遍,之后再细细思考,需要的话,可以google查询我没有覆盖到的具体用法。

看到文章的大神可以私信我改进的方向,公共区域给我留点面子,谢谢。

我第一次学习Python3时,把基础教程过了一边。呵呵呵,看完第二页,第一页的知识点已经忘了。 So happy. 后来才意识到直接上手,哪里不会查哪里才是正确的打开方式。

这个机器学习的案例和数据来自机器学习竞赛网站Kaggle的入门案例,大家做完了之后可以看到自己在9000+参赛者的排名

Titanic: Machine Learning from Disaster

www.kaggle.com/c/titanic

目的是根据泰坦尼克号乘客的基本信息来推测其生还机率。在这里大家可以顺便把这次用的数据下载好。

获取数据

登陆Kaggle, 没有的话注册一个先。

在这个页面获取Titanic的数据

https://www.kaggle.com/c/titanic/data

同时下载test.csv, 和 train.csv.

train.csv文件里包含一部分乘客的信息,和他们是否生还的结果。

test.csv文件里只有乘客信息,没有结果。

我们要观察train.csv里什么样的乘客更容易生还,或死亡。

来根据test.csv的乘客信息,推测他们的生还结果。

这种文件格式可以用excel打开,大家可以打开观察一下。因为这个文件比较小,太大的文件就打不开了。

CSV也可以用笔记本打开,就会发现它里面所有的数据都是用逗号分隔的,大家知道就好。之后会用到。

安装Python3 和PyCharm

首先下载python3

https://www.python.org/downloads/release/python-364/

在上面链接的最后部分选择适合自己系统的安装器(installer)。

接着向大家严重安利对新手超级友好的PyCharm, 清爽干净上档次,还免费。同时也避免了很多新手容易遇到的类似环境设置问题。反正下载这个就对了。超级省心!

PyCharm = Python的衣服(我们叫shell)

下载时,请选择免费的Community版本。呵呵呵,贫穷如我。

https://www.jetbrains.com/pycharm/download

在下面的setup步骤中,32位或者64位大家可以自己按照电脑选择下

下面的.py是关联Python的文件格式,大家可以打勾。

最底下的Jetbrain,我选择先不下载。

安装中,UI theme的选择我比较喜欢Darcula, 感觉比较炫酷,并且,嗯...不会读。

安装好了以后,打开PyCharm, 新建一个project, 我给它起名叫titanic。

接着会出现tips窗口,直接关掉就好啦(我上次看了二十分钟还没看完,放弃了...)

现在界面是这个样子

干净清爽大气高端上档次,我好喜欢!!!!

问题来了,说了半天,到底什么是Python?

我感觉Python是让电脑干活的的一种语言。很乖很听话,你让他倒水他就倒水,让他做饭他就做饭,唯命是从,这就是Python.

以我浅薄的理解,用户和Python有两种姿势的play(交流), 嘿嘿嘿。

第一种交流方式,点击Pycharm左上角File, 然后new scratch file. 然后在语言里选择Python.

这是写程序的交流, 你可以通过写程序告诉python, 他先干嘛再干嘛,然后点击运行,达成你想要的结果。

举个例子,假如有个女朋友,你写个行动手册告诉她。“Baby,你去桌子上拿一个水杯,然后去饮水机, 接水,走回来,温柔的说‘啊’, 然后喂我喝水。” 好了点击运行(Run)手册。 你就可以喝到水了。

这张方式叫做模块(Module),会形成一个 Python 文件,以.py结尾

第二种交流方式,点击Pycharm左上角Tools, 选择Python Console.

这是一种互动的交流。

举个例子,假如有个女朋友:

我: “Baby, 你去桌子上拿个水杯。”

“女朋友”:“拿到了”

我: “去饮水机接水”

“女朋友”:“接好了”

我: “走回来”

。。。。。。。

大概这个流程,一个步骤,一个动作,一个步骤,再一个动作的走。

这次我们会用到第二种, 大家现在可以把scratch_1.py 关掉了, 把空间留给Python Console就好。现在长这样。

整个项目的脉络大概是这样的:

观察数据(买菜),主要通过画图,来了解乘客基本信息,和他们生还率的关系

清理数据(切菜), 把文字数据转换成计算机可以分析的数字。(同时去掉不相关的数据)

建立机器学习模型(炒菜), 让机器分析数据, 寻找变量间的关系,最后做预测

安装我们这次要用的“包”(是别人写好的模块)

不是这个包!!!!


Python的包可以理解为帮助我们达成目标的小工具。

举个例子,

上图就是一种为达到目的,很实用的小工具。

为了安装包,打开pycharm左下角的小按钮,选择Terminal (Python Console不见了没关系,可以随时用老办法打开)。

我们这次要用的小工具有

pandas: 数据处理小能手

numpy: 数据处理小能手2

matplotlib: 画画小能手

seaborn: 画画小能手2

sklearn: 机器学习小能手

接下来依次输入以下代码到Terminal(只可以手打,每打完一行要按回车,安装完一个再安装下一个)

pip install pandas

pip install numpy

pip install matplotlib

pip install seaborn

pip install sklearn

pip 是用来安装其他包的小工具。

安装好了以后就可以退出Terminal了,再次打开Python Console.

包安装好了以后,要先在Python Console中加载才可以使用,可以在Python Console先加载 pandas, matplotlib 和 umpy三个包,Python不见了的话可以用前面的方法调出来:

在编程的时候,想换行的话可以按住shift再按enter

import pandas as pdpd.options.display.max_columns = 100from matplotlib import pyplot as pltimport matplotlibmatplotlib.style.use('ggplot')import numpy as np

import 是加载包的命令, 后面跟包的名字, as后面是你给包设定的比较方便打字的昵称。

第二行是对使用包的设定。

大家可以复制粘贴,然后回车,这里不会有任何反应,光标会重新出现。

加载和可视化分析数据

在Python Console输入以下代码。

这行代码大概可以理解成:设定新变量data, 并且让data等于train.csv里面的数据。

注意这里我们用到了包pandas的昵称(pd),并且使用了它其中的一项的功能read_csv.

括号里要改文件地址,因为现在的地址文件在我电脑上的位置,大家应该是不一样的。值得注意的WINDOWS地址里的斜杠和Python是反的。大家观察下。

相信大家的都能找到写出来,注意地址两端保留单引号。

之后data就代表了train.csv里的所有数据,数据类型是数据框(dataframe)其实很像excel。

data = pd.read_csv('C:/Users/Razer/Downloads/train.csv')

之后我们再敲一行代码看看都有哪些数据。

data.shape

返回(891, 12), 意思是有891行和12个列。

再使用data.head查看前五列,顺便一提数据框里的NaN代表缺失值

data.head()

返回


之后用describe查看数据的数值特征

data.describe()


大家可以看到有八个信息, 分别是数量,平均值,中位数,最小值,第一四分位数,中位数, 第三四分位数,最大值。

举例,看到Survived的平均值,大家就知道大概有38%的人生还。

看Age, 就知道大部分都是年轻人和中年人来船上浪,最老的人80岁。

重要的是,Age好像只有714个值,少了177个值。

这里为了接下来画图,我们简单的用代码把这些值换成Age的中位数。

用的是fillna功能,也是pandas的函数。用来替换缺失值。

data['Age']的意思是在data这个数据框里,选出名字是Age的这个列来作为操作对象(Python中所有的文本都要加引号像这里的'Age')

然后使用fillna, 之后在小括号里设置了使用data中的Age的中位数替换缺失值。

更多的使用方法大家可以搜一搜fillna,很容易查到, 之后又没见过的函数,想的话都可以搜搜。

data['Age'].fillna(data['Age'].median(), inplace=True)

运行之后就替换成功。大家可以再用一遍data.describe, 就会看到age被填满了。

接下来就是我们的推测过程了,大家都知道,在titanic这个电影中,逃生的时候是女士优先的,所以我们大胆猜测,女士幸存率更大一些。

这里我们用pandas的功能来画图,

survived_sex = data[data['Survived']==1]['Sex'].value_counts()dead_sex = data[data['Survived']==0]['Sex'].value_counts()df = pd.DataFrame([survived_sex,dead_sex])df.index = ['Survived','Dead']df.plot(kind='bar',stacked=True, figsize=(15,8))

通过上面的代码,我们创建了一个新的数据框survived_sex。

等号右边 data[data['Survived']==1] 代表选出data数据框里所有的幸存者数据['Survived']==1;接着['Sex'].value_counts(), 把选出的数据按性别记总数。

survived_sex长这个样子

dead_sex 同理

然后用

df = pd.DataFrame([survived_sex,dead_sex]) 把两个数据框合成一个数据框

df.index = ['Survived','Dead'] 并且给它们加上行标签

df长这样

最后通过df.plot(kind='bar',stacked=True, figsize=(15,8)) 把数据用重叠的柱状图画出来


大家可以看到,男同胞死亡率高很多,女同胞幸存几率更大。

接下来我们用matplotlib看看不同年龄的幸存率。

figure = plt.figure(figsize=(15,8))plt.hist([data[data['Survived']==1]['Age'], data[data['Survived']==0]['Age']], stacked=True, color = ['g','r'],

bins = 30,label = ['Survived','Dead'])plt.xlabel('Age')plt.ylabel('Number of passengers')plt.legend()

这个包是另一种画图思路,先通过第一行代码创建一个画板,然后一件一件的往上面画东西。

用plt.hist先画重叠直方图。

data['Survived']==1]['Age'] 代表统计不同年龄活下来的数量。

data['Survived']==0]['Age'] 代表统计不同年龄死亡的数量。

然后用plt.xlable和plt.ylable写用哪些数据做x和y轴。

最后写legend,显示标签。大家感兴趣的话这有个链接教matplotlib。

https://python4mpia.github.io/plotting/advanced.html

这次很明显未成年人活下来的几率更大。大家都是好人啊。

再看一个船票价格和生还率的关系,还是matplotlib

figure = plt.figure(figsize=(15,8))plt.hist([data[data['Survived']==1]['Fare'],data[data['Survived']==0]['Fare']], stacked=True, color = ['g','r'],

bins = 30,label = ['Survived','Dead'])plt.xlabel('Fare')plt.ylabel('Number of passengers')plt.legend()

社会很现实 越有钱生存几率越大

最后再看一组Embark的数据,说不定登船口也决定了乘客的位置是不是可以更好地逃生

又回到pandas了。

survived_embark = data[data['Survived']==1]['Embarked'].value_counts()dead_embark = data[data['Survived']==0]['Embarked'].value_counts()df = pd.DataFrame([survived_embark,dead_embark])df.index = ['Survived','Dead']df.plot(kind='bar', stacked=True, figsize=(15,8))

大家看在S和Q登船的死亡率更高一些,C口的生还率则高一些

然后我们大胆的猜测不同价格的票登船口不一样,有钱人应该在C登船(matplotlib)

所以我们看看不同登船地点的平均票价

ax = plt.subplot()ax.set_ylabel('Average fare')data.groupby('Embarked').mean()['Fare'].plot(kind='bar',figsize=(15,8), ax = ax)

果然,有钱就是好啊

其实Embarked, Fare, Cabin, Pclass 应该都是和价格相关的。大家也可以画更多的图来观察数据的相关性。

数据清理阶段

上一步的画图中,是让人去看图分析

在这一步我们要把数据转换成纯数字的数据

因为计算机只能看懂数字,因为只有计算机可以看懂数据了,才可以由计算机代替人去海量分析数据之间的关系。

首先我们导入原始数据,相信大家都有经验啦, 不要忘记替换文件目录

train = pd.read_csv('C:/Users/Razer/Downloads/train.csv')test = pd.read_csv('C:/Users/Razer/Downloads/test.csv')

然后去掉train里的Survived数据,使train和test保持一致,因为test是没有Survived这一列的,列数如果不同,就不能合并数据框。

train.drop('Survived', 1, inplace=True)

创建新的变量 combined, 把两个文件的数据放到一起,方便处理

在第一行代码里,合并数据框的操作是用.append函数做到的

在第二行里我们.reset_index为combined创建一个新的序列号,从数字1到最后,因为刚合并完的序号是乱的

在第三行里我们删除老的序列号。

combined = train.append(test)combined.reset_index(inplace=True)combined.drop('index', inplace=True, axis=1)

在这里要向大家介绍一点新知识,自己创建函数

举个例子,第二种方法,刚才的几行代码也可以这样写,不要忘了改目录哈

def get_combined_data():

train = pd.read_csv('C:/Users/Razer/Downloads/train.csv')

test = pd.read_csv('C:/Users/Razer/Downloads/test.csv')

train.drop('Survived', 1, inplace=True)

combined = train.append(test)

combined.reset_index(inplace=True)

combined.drop('index', inplace=True, axis=1)

return combined

直接按回车,好啦,我们自己的函数定义好啦

我先解释一下这个函数的代码

第一行首先用def表示我们要写函数啦,def后面蓝色的代表我们想要的函数的名字,在后面的括号里可以设置函数可以用到的变量,这个我们后面还有例子要说明。

然后看到最后一行return combined, 意思是我们通过这个函数会得到combined这个值。

运行函数的话 我们要输入函数的名字

get_combined_data()

之后Python Console会返回所有的数据

这个时候我们要比较一下两种方法的区别

第一种方法: 创建了三个新变量 train, test, combined。并且他们是全球变量(global variable), 意思是任何函数都可以使用global函数调用他们,之后会看到。

第二种方法:没有创建任何全球变量,这种方法创建的是本地变量(local variable)。这种变量只能在函数运行中使用,并不会产生全球变量。

所以说我们刚才运行函数,并没有想第一种方法一样产生新的全球变量train, test 和combined, 它只返回一个结果。

怎么获得全球变量呢? 机智如我

combined = get_combined_data()

好啦,直接把函数结果赋值给一个新的全球变量就好

可以用head看一下

combined.head()

是不是很爽,哈哈哈哈

接下来我们继续搞数据,我们接下来会用到Python的列表,元组,字典这三个东西,建议大家看一下“菜鸟教程”里的这三个部分,只看这三个就好。地址在这里

http://www.runoob.com/python3/python3-list.html

现在我们想把名字转化成更有意义的类别,因为名字里的敬称代表着不同的社会地位,我们通过敬称,把人做一个分类,注意这里用到了全球变量combined, 我们用global使用它。

def get_titles():

global combined

# 第一步

combined['Title'] = combined['Name'].map(lambda ame:name.split(',')[1].split('.')[0].strip())

# 第二步

Title_Dictionary = {

"Capt": "Officer",

"Col": "Officer",

"Major": "Officer",

"Jonkheer": "Royalty",

"Don": "Royalty",

"Sir" : "Royalty",

"Dr": "Officer",

"Rev": "Officer",

"the Countess":"Royalty",

"Dona": "Royalty",

"Mme": "Mrs",

"Mlle": "Miss",

"Ms": "Mrs",

"Mr" : "Mr",

"Mrs" : "Mrs",

"Miss" : "Miss",

"Master" : "Master",

"Lady" : "Royalty"

}

# 第三步

combined['Title'] = combined.Title.map(Title_Dictionary)

第一步,提取名字里的敬称

先看等号左边,combined['Title']这里的意思是为combined这个数据框创建一个新的列Title

等号右边我们先看后面括号里的内容,lambda是一个匿名函数。是的它也是一个函数,是简化版的,没有名字,只能写一行代码实现简单的功能。

在lambda这个小函数里,我们给它的本地变量起名叫name,这个本地变量叫什么都可以,你起名叫shit也可以运行。这个本地变量代表的是括号外的combined数据框name这一列的每一个值。

所以说等号右边就是会把着combined数据框里每一个name按照lambda里面的小小的匿名函数运行一遍,并且用.map赋值。

这个函数是干嘛的呢?它用.split函数把每个字符串string(也就是我们的每一个name)按照“,”分裂成包含n个元素。

例如 “ba,ba” 会变成 ['ba', 'ba'] 包含两个元素的列表。我们的名字分裂后里第二个的元素一般是名字的敬称,小姐姐 Miss, 之类的。我们用[1]这个表达式选出刚才列表里的第二个元素,然后再用split('.')[0]删除敬称里面的“.” 再用.strip()删掉除了字符之外的东西比如字符两头的空格。

最后,等号左右两边连在一起,我们牛逼哄哄的用一行代码把为combined数据框创建了新的列Tittle, 并且用敬称赋值。

第二步 , 对敬称做一个分类

我们创建了一个字典,这个字典就像一个目录,告诉Python每个敬称,代表什么样的社会地位,我们这里有工作人员,由贵族,有老百姓什么的。

第三步 我们把title里的敬称替换成新的分类。

#号在Python里是备注的意思,并不会执行

好啦, 大家运行一下

get_titles()

这个函数会直接对我们的combined全球变量做出更改。

大家可以再用head查看一下,产生了一个新的列 Title.

combined.head()

接下来我们要填充缺失的年龄,大家可以用.info看一下

combined.info()

看起来缺失了263个年龄

不怕不怕,我们决定统计一下按照性别sex, 票的等级Pclass, 社会地位Title, 把所有人分成不同的小组,然后按照缺失信息的那个人所在组的年龄中位数指定为他们的年龄。

grouped = combined.groupby(['Sex','Pclass','Title'])grouped_median = grouped.median()

然后直接打出看看

grouped_median

我们接下来就要为缺失值制定年龄啦

我们接下来要用到循环概念,大概是对一组数据中的每一个值做重复的事情。

没接触过这个概念的可以先看一下“菜鸟教程”的条件控制和循环 这两页

这是条件控制的链接

http://www.runoob.com/python3/python3-conditional-statements.html

好啦,上替换缺失值的代码

# 第一层def process_age(): global combined

# 第二层

def fillAges(row, grouped_median):

if row['Sex']=='female' and row['Pclass'] == 1:

if row['Title'] == 'Miss':

return grouped_median.loc['female', 1, 'Miss']['Age']

elif row['Title'] == 'Mrs':

return grouped_median.loc['female', 1, 'Mrs']['Age']

elif row['Title'] == 'Officer':

return grouped_median.loc['female', 1, 'Officer']['Age']

elif row['Title'] == 'Royalty':

return grouped_median.loc['female', 1, 'Royalty']['Age']

elif row['Sex']=='female' and row['Pclass'] == 2:

if row['Title'] == 'Miss':

return grouped_median.loc['female', 2, 'Miss']['Age']

elif row['Title'] == 'Mrs':

return grouped_median.loc['female', 2, 'Mrs']['Age']

elif row['Sex']=='female' and row['Pclass'] == 3:

if row['Title'] == 'Miss':

return grouped_median.loc['female', 3, 'Miss']['Age']

elif row['Title'] == 'Mrs':

return grouped_median.loc['female', 3, 'Mrs']['Age']

elif row['Sex']=='male' and row['Pclass'] == 1:

if row['Title'] == 'Master':

return grouped_median.loc['male', 1, 'Master']['Age']

elif row['Title'] == 'Mr':

return grouped_median.loc['male', 1, 'Mr']['Age']

elif row['Title'] == 'Officer':

return grouped_median.loc['male', 1, 'Officer']['Age']

elif row['Title'] == 'Royalty':

return grouped_median.loc['male', 1, 'Royalty']['Age']

elif row['Sex']=='male' and row['Pclass'] == 2:

if row['Title'] == 'Master':

return grouped_median.loc['male', 2, 'Master']['Age']

elif row['Title'] == 'Mr':

return grouped_median.loc['male', 2, 'Mr']['Age']

elif row['Title'] == 'Officer':

return grouped_median.loc['male', 2, 'Officer']['Age']

elif row['Sex']=='male' and row['Pclass'] == 3:

if row['Title'] == 'Master':

return grouped_median.loc['male', 3, 'Master']['Age']

elif row['Title'] == 'Mr':

return grouped_median.loc['male', 3, 'Mr']['Age']

#第二层里运行第三层也就是我们刚写的fillAge函数

combined.Age = combined.apply(lambda r : fillAges(r, grouped_median) if p.isnan(r['Age'])

else r['Age'], axis=1)

这一段有意思的地方是函数里面套着函数,循环里面套着循环。呵呵呵。感受一下Python版本的盗梦空间。(好巧,泰坦尼克号也是小李子主演)

这里还要注意Python代码运行时候是先从外到里,然后才是从上到下。

区分从外到里的方法就是看代码的缩进也就是TAB键,没向里一层,就多用一次TAB。

注意了第一步也就是最外层是 def process_age(): 这是整个函数的总起。没有TAB

然后TAB 一下 到第二层 我们定义了一个新函数 fileAge,但是它现在并没有运行。我们在第二层最后的一行代码中调用了它,我觉得就像是进入了第三层。

我们先讲讲fileAge这个函数,

它定义了两个本地变量,row 和 grouped_median,注意这里名字是什么无所谓,这里的本地变量grouped_median和我们上一步的全球变量grouped_median他们有本质的区别。但是我们一会会把外面的全球变量grouped_median的值赋给里面的本地变量grouped_median。

在这里函数里利用条件控制(大家都看了吧就是if和elif)把每一行数据划分到不同的小组里并且按照上一步的中位数赋值。这里用的新函数是.loc 和Excel里的VLOOKUP函数非常相似。大概就是设定条件搜索结果的用法。

然后讲讲最后一行代码

等号左边选出combined数据框里的Age列,

右边用.apply给combined数据框里每一行的age赋值。

最后讲讲lambda这个匿名循环

它的变量叫r, 也就是combined数据框的每一行,数据框在循环里以行为一个单位。

好,选出一行,然后if这一行没有值,就调用我们写的fileAge来填充空值,我们调用fileAge的时候,在小括号里设定了(r, grouped_median),r就是每一行,grouped_median这里指的是我们的全球变量grouped_median。这里就是指定了fillAges(row, grouped_median)里面的row和grouped_median两个本地变量,等于(r, grouped_median)的值。

else if 其他情况也就是已经有年龄的,就赋值它这一行原本的年龄。global combined

好啦,运行一下

process_age()

这时候再试一次.info

combined.info()

很好,很成功的填好了Age的所有空值。

接下来我们删除姓名这列没什么价值的列

并且把社会地位Title变成虚拟变量dummy variables,用.concat加入到combined数据框里。

然后再删除Title

举例dummy variables 大概就像下图的调查问卷

在右边选值的地方有五个列, 从不同意到同意,每一行这五个值只能选一个。

在python的世界里,选了就是数字一,没选就是数字0.

我们的社会地位Title转换完了在combined数据框里长这样,大家可以对比理解一下

def process_names():

global combined

# we clean the Name variable

combined.drop('Name',axis=1,inplace=True)

# encoding in dummy variable

titles_dummies = pd.get_dummies(combined['Title'],prefix='Title')

combined = pd.concat([combined,titles_dummies],axis=1)

# removing the title variable

combined.drop('Title',axis=1,inplace=True)

好啦, 别忘了运行

process_names()

这个时候不用我说,相信大家也会用shape, info, head,describe 来看一下我们的数据了吧。

接下来给缺失的Fares赋值一个平均数,因为只缺一个,就不用很麻烦了。

combined.Fare.fillna(combined.Fare.mean(), inplace=True)

然后是Embarked的空值填充,赋值S,就缺两个值,所以随便选的,因为S比较多。

然后把Embarded也转换成虚拟变量,加入combined数据框里。

def process_embarked():

global combined combined.Embarked.fillna('S', inplace=True)

# dummy encoding

embarked_dummies = pd.get_dummies(combined['Embarked'],prefix='Embarked')

combined = pd.concat([combined,embarked_dummies],axis=1)

combined.drop('Embarked',axis=1,inplace=True)

运行

process_embarked()

接下来把没有空缺的Cabin留首字母, 空缺的Cabin的值转化成“U” 表示unknow,

def process_cabin():

global combined

# replacing missing cabins with U (for Uknown)

combined.Cabin.fillna('U', inplace=True)

# mapping each Cabin value with the cabin letter

combined['Cabin'] = combined['Cabin'].map(lambda c : c[0])

# dummy encoding ...

cabin_dummies = pd.get_dummies(combined['Cabin'], prefix='Cabin')

combined = pd.concat([combined,cabin_dummies], axis=1)

combined.drop('Cabin', axis=1, inplace=True)

然后运行

process_cabin()

接着把combined数据框的sex列里面的female和male两个字符值换成数字0,1.

combined['Sex'] = combined['Sex'].map({'male':1,'female':0})

把舱位等级Pclass换成虚拟变量,

def process_pclass():

global combined

# encoding into 3 categories:

pclass_dummies = pd.get_dummies(combined['Pclass'], prefix="Pclass")

# adding dummy variables

combined = pd.concat([combined,pclass_dummies],axis=1)

# removing "Pclass"

combined.drop('Pclass',axis=1,inplace=True)

运行

process_pclass()

下一步,保留Ticket的前缀,

这里用到.replace删掉Ticket里没意义的符号,

然后有map,lambda,strip配合帮助清理ticket号码前后的空格

然后是新知识filter函数

filter帮助过滤我们需要的值,他的小括号里有两个值,第一个是条件,第二个是将被过滤的对象

如果条件满足就会返回“Ture", 不对就返回"False"。我们这里的条件是lambda匿名函数。

在我们这个匿名函数里,ticket的值是数字的话,就通过.isdigit返回 "Ture",但是我们前面有个not, 所以会再反转一下,再变回 “False”。反之亦然。

所以总的来说,filter会帮助我们筛选出带有字母的票号,只有数字的会设为空值。

对于清理完之后所有空值的我们指定值“XXX” 表示不知道

接着老套路,创建Ticket虚拟变量

def process_ticket():

global combined

# a function that extracts each prefix of the ticket, returns 'XXX' if no prefix (i.e the ticket is a digit)

def cleanTicket(ticket):

ticket = ticket.replace('.','')

ticket = ticket.replace('/','')

ticket = ticket.split()

ticket = map(lambda t : t.strip(), ticket)

ticket = filter(lambda t : not t.isdigit(), ticket) x=list(ticket)

if len(x) > 0:

return x[0]

else:

return 'XXX'

# Extracting dummy variables from tickets:

combined['Ticket'] = combined['Ticket'].map(cleanTicket)

tickets_dummies = pd.get_dummies(combined['Ticket'], prefix='Ticket')

combined = pd.concat([combined, tickets_dummies], axis=1)

combined.drop('Ticket', inplace=True, axis=1)

运行

process_ticket()

我们接着处理Parch和SibSp, 我们把他们合为一体变成Family Size

并且直接生成虚拟变量

def process_family():

global combined

# introducing a new feature : the size of families (including the passenger)

combined['FamilySize'] = combined['Parch'] + combined['SibSp'] + 1

# introducing other features based on the family size

combined['Singleton'] = combined['FamilySize'].map(lambda s: 1 if s == 1 else 0)

combined['SmallFamily'] = combined['FamilySize'].map(lambda s: 1 if 2<=s<=4 else 0)

combined['LargeFamily'] = combined['FamilySize'].map(lambda s: 1 if 5<=s else 0)

运行

process_family()

好啦到此为止,我们数据准备工作完成啦。总计68列。

组建机器学习模型

首先简单了解下机器学习。机器学习是人工智能领域的概念。

它可以分为监督学习,无监督学习,半监督学习,增强学习。

举例:

监督学习,我们这次就是监督学习,在train文件里有乘客信息和是否生还的结果,我们就要观察train文件里面不同类型的乘客的生还可能性。来推测test文件里乘客的生还结果。

大概就是给定两个结果,存活或者死亡,把所有人分到这两个类别里。只要这两种结果

无监督学习,直接给所有乘客的信息,让电脑自动把他们按相似的特征分成不同的组。例如,我和吴彦祖被分到一起,代表我们是比较相似的人。与无监督学习不一样的是,这里并没有固定要分的结果,最后分成的组的数目是不一定的。

半监督学习, 前两者的结合。

增强学习,大概就是像训练小动物一样,通过奖罚,让它们知道怎么做。比如当红炸子鸡,对抗网络。

监督学习有很多模型我们今天要用的是随机森林,随机森林是基于决策树的。

决策树大概长这样,从上往下每个节点(方块)有不同的选择(线),最下面产生n个决策也就是Leaf(叶子),(椭圆)。 顺下来,很容易就得知一个西瓜的好坏。

随机森林是决策树的增强版本,它有两个随机过程构成。核心思想是“三个臭皮匠赛过诸葛亮”。

第一个随机过程,在原始数据集中,有放回的随机抽样组成很多个新的数据集。这就代表了每个新的数据集中可能有重复的原始数据集的某条数据,因为是有放回的抽样。重点是每个新的数据集都是不相同的,就可以理解为我们用有限的数据,创造出了更多的数据。增大了样本量。(P.S.学过统计的同学可以联想下中心极限定理,我心虚的感觉它们有异曲同工之妙)

第二个随机过程,是我们在对每个新的数据集构建决策树的时候,要在每个分叉的节点选择用哪个特征来决策。这个选择特征过程是随机的。比如总计有十个特征,在遇到新的分差节点时,我们设定在十个里面随机选出五个,然后在设定某种策略(比如信息增益),在这五个中随机选出一个特征作为这个节点的特征。

所以通过两个随机过程我们得到了很多不一样的决策树,然后我们就可以以统计一下这些树的结果(少数服从多数之类的),对每个样本进行预测。

好啦,回到代码部分。

我们要干的第一件事就是评估一下我们刚才68列特征的对预测结果准确性的好坏。

from sklearn.pipeline import make_pipelinefrom sklearn.ensemble import RandomForestClassifierfrom sklearn.feature_selection import SelectKBestfrom sklearn.cross_validation import StratifiedKFoldfrom sklearn.grid_search import GridSearchCVfrom sklearn.ensemble.gradient_boosting import GradientBoostingClassifierfrom sklearn.cross_validation import cross_val_score

加载一堆包,有warning不用太担心。

然后我们创建以下几个全球变量。

targets是我们验证结果准确度的正确答案

train是有答案的combined数据框的前891个

test是891个之后的样本,也是我们最终要预测并提交的结果的样本

train0 = pd.read_csv('C:/Users/Razer/Downloads/train.csv')targets = train0.Survivedtrain = combined.head(891)test = combined.iloc[891:]

接着加载包,并且用RandomForestClassifier和.fit创建一个分类器clf,我觉得clf就是个简易版的随机森林模型。给我们筛选特征的时候先用一下。

from sklearn.ensemble import RandomForestClassifierfrom sklearn.feature_selection import SelectFromModelclf = RandomForestClassifier(n_estimators=50, max_features='sqrt')clf = clf.fit(train, targets)

然后我们通过clf分类器和画图来看一下我们68个特征对优化函数的重要性

第一行代码创建的空数据框features

第二行和第三行给数据框赋值两列,feature(train的列名)和importance重要性(通过)

features = pd.DataFrame()features['feature'] = train.columnsfeatures['importance'] = clf.feature_importances_features.sort_values(by=['importance'], ascending=True, inplace=True)features.set_index('feature', inplace=True)features.plot(kind='barh', figsize=(20, 20))

可以清楚地看到,Sex, PassengerId, Fare, Title, 等等这些比较重要。

接下来我们用SelectFromModel选出排名高于重要性平均值的特征,

然后用.transform创建只包含这些特征的train_reduced变量

model = SelectFromModel(clf, prefit=True)train_reduced = model.transform(train)

我们来看看train_reduced

train_reduced.shape

(891, 14)只剩下14列了。

然后创建一个计算准确性的函数,一会测试我们结果准确度用,用到了cross_val_score函数,通过设定CV参数把要测试的数据集combined 分成五个小数据集,然后互相对比分析,用平均值代表准确度。大家感兴趣的可以查一下cross-validation strategies。

def compute_score(clf, X, y, scoring='accuracy'):

xval = cross_val_score(clf, X, y, cv = 5, scoring=scoring)

return np.mean(xval)

接下来设置我们随机森林模型的参数

parameters = {'bootstrap': False, 'min_samples_leaf': 3, 'n_estimators': 50, 'min_samples_split': 10, 'max_features': 'sqrt', 'max_depth': 6}

model = RandomForestClassifier(**parameters)model.fit(train, targets)

具体的参数设置技巧,大家可以查看以下网页

https://www.analyticsvidhya.com/blog/2015/06/tuning-random-forest-model/

然后运行函数看看成果

compute_score(model, train, targets, scoring='accuracy')

结果还是不错的。准确率有百分之八十多

接下来我们用这个模型来预测test里的数据,不要忘记改文件目录哈,一个输入的,一个输出的。

输出地址就是你想创建结果的地址,最后的文件名可以自己随便设立。。

output = model.predict(test).astype(int)df_output = pd.DataFrame()aux = pd.read_csv('C:/Users/Razer/Downloads/test.csv')df_output['PassengerId'] = aux['PassengerId']df_output['Survived'] = outputdf_output[['PassengerId','Survived']].to_csv('C:/Users/Razer/Downloads/output5.csv',index=False)

之后大家就可以去Kaggle提交成绩啦。

恭喜各位。我用同样的模型拿到了0.80861的准确率,在9000多参赛者里是排名前10%的分数。

最后要说的是,这个Titanic是入门的练手案例,用来熟悉机器学习的方法,大家胜负心不用太强,这个分数还是可以的。

最重要的是本笔记假象的读者是完全不会python的,希望大家看完后对机器学习和python有更深入的理解

上一篇:程序员到底是一个什么职业?
下一篇:如何快速清除网络负面信息,清除网络负面的方法

马上预约三天免费体验课

姓名:

电话:

选择城市和中心
贵州省

广西省

海南省