这是本篇文章是《机器学习入门》系列文章的第二篇,该系列有如下文章:
《机器学习入门——基础篇》
《机器学习入门——实战篇之监督学习》
《机器学习入门——实战篇之非监督学习》
《机器学习入门——实战篇之深度学习》
《机器学习入门——实战篇之强化学习》
闲话少说,言归正传。
大家还记得我们提到过监督学习里面的几个名词,线性回归,感知器,决策树,朴素贝叶斯,支持向量机。下文中我们就一一来看看在Python中怎么使用这些工具。
说到Python,相信在攻城狮领域已经不用过多介绍,它可谓是当红炸子鸡,忽如一夜春风来,千人万人学Python。为什么能够这么热,跟这门语言的平易近人有很大关系,乍一看,语法简单,调用简单,没有C++那么多恐怖的特性,也不强调什么对象不对象的,但好像也啥都能干。这就是许多服务器端脚本语言的特点,并且也是动态语言的特点,灵活方便,尤其是网络协议和工具封装的好。并且,它还赶上了机器学习的又一次大潮(我为什么用了又字……好吧,历史上确实有好几次大潮,周期性呈现……),很好的实现了TensorFlow的API,可谓一路高歌猛进。好了,还不懂Python的同学可以简单学习一下,本文要求有一定的Python基础,并且最好安装一个Python环境,一边探讨一边做实验。
一、线性回归
前文我提到过这么一幅图:
对了,就是预测股市大盘的这个曲线,我们通过年初和年中两个点,预测出了年末大盘走势。当然了,这只是一个理想形态。不管怎么说,还是表现出了线性回归的特性。我们看看Python里面怎么实现这种预测。
# 引入一个计算向量数据很方便的工具pandas
import pandas as pd
# 再引入一个我们要的线性回归库 LinearRegression
from sklearn.linear_model import LinearRegression
# 用刚才的pandas读取一个文件,这个文件可以理解成有许多的散列点(x, y)
# CSV文件就是用逗号分开的一些值,按行排好
data = pd.read_csv("file.csv")
# 实例化一个线性回归模型
model = LinearRegression()
# 把数据导入这个模型,让模型适应,也就是训练啦,一个fit搞定
# 其中这个X和Y可以理解为两个向量,就是两列数,一一对应起来
model.fit(data[['X']], data[['Y']])
# 然后我们给出一个值,并用print看看预测数来的值,一切搞定!
laos_life_exp = bmi_life_model.predict(21.07931)
print(laos_life_exp)
是不是简单清晰,不过想要实验的同学,需要自己准备一份数据文件,把数据读进去,然后自己调用试一试。
二、感知器
这个东西比线性回归稍微复杂一些,我们还是先回顾一下基础篇提到的图:
就是这个图了,一条红线,分开了正常人和疯子。我们来看看类似的问题怎么用Python来实现。
# 这次我们又换了一种工具,叫numpy,也是一个数据处理库,比pandas更加底层一些
import numpy as np
# 设置一个随机数的种子,用来生成随机数,为什么是42呢,因为这是宇宙最终极的答案
# 参考电影《银河系漫游指南》
np.random.seed(42)
# 定义一个函数,很简单,正数返回1,负数返回0
def oneStep(t):
if t >= 0:
return 1
return 0
# 定义一个预测函数
def prediction(X, W, b):
# 这是一个矩阵相乘函数np.matmul
return oneStep((np.matmul(X,W)+b)[0])
# 这里就是我们的真实大Boss所在了,感知函数
# 感知器的核心思想就是把一条线摆在两堆不同种类的样本中间
# 从而实现让两堆样本分开的结果
# X是一大堆数值,对应一大堆表示y,W就是权重
# 每次取出一个X的值,乘以权重,加上一个b值,不就是一条一元一次的直线嘛
# 看看这条线是不是摆对了位置,如果不对,就调整一下
# 重复以上的步骤直到满意
def perceptronStep(X, y, W, b, learn_rate = 0.01):
# Fill in code
for item_x, item_y in zip(X, y):
y_p = prediction(item_x, W, b)
if item_y - y_p == 1:
W[0] += item_x[0]*learn_rate
W[1] += item_x[1]*learn_rate
b += learn_rate
elif item_y - y_p == -1:
W[0] -= item_x[0]*learn_rate
W[1] -= item_x[1]*learn_rate
b -= learn_rate
return W, b
# 下面就开始寻找我们想要的那个线
# 这里有个学习速率0.01,就是决定每次移动的幅度的
def trainPerceptron (X, y, learn_rate = 0.01, num_epochs = 25):
x_min, x_max = min(X.T[0]), max(X.T[0])
y_min, y_max = min(X.T[1]), max(X.T[1])
W = np.array(np.random.rand(2,1))
b = np.random.rand(1)[0] + x_max
# 下面就要调用我们准备好的函数
boundary_lines = []
# 一遍一遍的迭代,25次
for i in range(num_epochs):
W, b = perceptronStep(X, y, W, b, learn_rate)
boundary_lines.append((-W[0]/W[1], -b/W[1]))
return boundary_lines
不管你看懂了没有,秘诀就在于,反复的实验,并且把里面的数据结构打印出来对比学习。
三、决策树
老规矩,从复习决策树的图形开始:
对,就是这个图,我们举例用了决策树做垃圾分类,实际上,决策树可以干的事情可多了,例如,它居然可以被用来预测一次灾难的生还率。下面,我们就用决策树来预测“泰坦尼克号”乘客的生还率!
# 先是引入两个我们已经熟悉的库
import numpy as np
import pandas as pd
# 再引入一个用于显示数据的库
from IPython.display import display # Allows the use of display() for DataFrames
# 仍然是随机数
import random
random.seed(42)
# 读入数据文件
in_file = 'data.csv'
full_data = pd.read_csv(in_file)
# 这里我们可以简单看一看数据长什么样子
display(full_data.head())
数据项目如下:
乘客ID
是否生还
客舱级别
名字
性别
年纪
同行兄弟姐妹人数
同行父母子女人数
票号
票价
仓号
登陆港口
# 因为是否生还属于一个结果属性,我们把它单拎出来,然后把结果去掉
outcomes = full_data['Survived']
features_raw = full_data.drop('Survived', axis = 1)
# 先对数据进行one-hot编码,也有人翻译成独热编码,好吧
# 不管什么名字就是类似于这样,001表示男,010表示女,100表示不知道
# 也就是用三个bit表示了三种情况,每个情况下只有一个bit被置位了
features = pd.get_dummies(features_raw)
# 这一步是把空的地方加上0
features = features.fillna(0.0)
# 下面动真格的了,引入了一个至关重要的库,能把训练集和测试集分开,就像图里这样
# 等等,啥是训练集,啥是测试集?训练集合就是用来训练模型的数据
# 但是训练好以后,模型到底能得多少分啊,那就测试一下,于是还需要测试集
# 之所以把两部分数据分开,就是为了防止过拟合……好吧,啥是过拟合
# 就好比考试先看了答案再考,能考不好么……,为了防止看答案,就把测试集先藏起来
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(features, outcomes, test_size=0.2, random_state=42)
# 引入主角决策树类库
from sklearn.tree import DecisionTreeClassifier
# 真正的训练就这么一下子!搞定
model = DecisionTreeClassifier()
model.fit(X_train, y_train)
# 模型训练完了,分别在训练集和测试集上预测一下嘛
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)
# 看看准确率,你会发现训练的准确率奇高,基本全对
# 但是拿出来测试集一试,就露馅了,只有0.8左右,但是也算足够好了
from sklearn.metrics import accuracy_score
train_accuracy = accuracy_score(y_train, y_train_pred)
test_accuracy = accuracy_score(y_test, y_test_pred)
到这里,大家是不是对一个训练加模型评分的过程有了全局性的认识呢?就是这么简单!
四、朴素贝叶斯
挑战越来越难啦,复习公式:
P(A|B) = P(B|A)P(A)/P(B)
这就是贝叶斯大魔王的定理,含义不再复述,可以查看我的前一篇文章,机器学习入门——基础篇。
这一次,我们要用贝叶斯大定理生成的模型来做垃圾邮件分类。垃圾邮件分类是一个二分问题,通常垃圾邮件的用词有其特殊性,我们就用模型来找到这种特殊性,从而以后再碰到类似邮件就可以分辨出来。
数据预处理的部分不再赘述,和前面的部分相去不大。关键是,为了引用贝叶斯模型,我们要用到另一个东西,“词袋”模型。简单说,就是许多的数学模型都要求输入数字,但是我们面对的是文本啊,像什么邮件啊,文章啊,都是文本,那么我们就简单的把这些文本里面的词做一个词频计数,不就变成了数字嘛!这就是词袋模型,像是把词放进袋子里,再数一数的意思。
# 引进相应的库
from sklearn.feature_extraction.text import CountVectorizer
# 然后用专门的方法就能得到最后的结果,这里我们引入了参数
# 分别是说处理英语,并且告知了英语单词的分隔方式
count_vector = CountVectorizer(documents, lowercase=True, token_pattern='(?u)\\b\\w\\w+\\b', stop_words='english')
# 然后我们就用这个“计数向量”这么fit一下
count_vector.fit(documents)
# 中间一大堆数据维度处理的过程我们省去,进入关键的代码
# 下面开始分割训练集和测试集
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df['sms_message'], df['label'], random_state=1)
# 来到关键的贝叶斯部分,动用了sklearn的贝叶斯模型
from sklearn.naive_bayes import MultinomialNB
naive_bayes = MultinomialNB()
# 简单的一个fit,又搞定了
naive_bayes.fit(training_data, y_train)
最后的评估部分我们省略了,可以自行去查看,提示,可以调用sklearn库的accuracy_score, precision_score, recall_score, f1_score这些东西看看。
贝叶斯大魔王也不过如此,我们继续,监督学习的最后一部分,支持向量机的实现。
五、支持向量机
闲言碎语不多讲,直接来到sklearn
# 引入支持向量机库
from sklearn.svm import SVC
# 实例化一个模型
model = SVC()
# 训练!
model.fit(x_values, y_values)
# 然后我们假设有一组数,那就可以预测啦
model.predict([ [0.2, 0.8], [0.5, 0.4] ])
上面这个过程如果太简单了,那我们就来一个有参数的
# kernel表示用什么计算核心,我们用多项式
# 如果内核是多项式,则此degree参数为内核中的最大单项式次数。
# C参数是惩罚参数,大了那么对于数据的拟合就会精准一点,但是,也可能过拟合,反之可推
model = SVC(kernel='poly', degree=4, C=0.1)
当然了,除了这样的一组参数,还可以选别的核,比如rbf核,对应gamma参数,可以自行去学习含义。
同样,最后可以用accuracy_score来评价模型训练的好坏。
这是本篇文章是《机器学习入门》系列文章的第二篇,该系列有如下文章:
《机器学习入门——基础篇》
《机器学习入门——实战篇之监督学习》
《机器学习入门——实战篇之非监督学习》
《机器学习入门——实战篇之深度学习》
《机器学习入门——实战篇之强化学习》