机器学习之监督学习

目录

1 监督学习

1.1 分类与回归

1.2 泛化、过拟合与欠拟合

1.3 监督学习算法

1.3.1 KNN(K-Nearest Neighbor)

1.3.2 线性模型

1.3.3 决策树

随机森林

梯度提升回归树(梯度提升机)

 


1 监督学习

1.1 分类与回归

监督学习问题主要有两种:分类(classification)与回归(regression)

分类问题的目标是预测类别标签(class label),包含二分类和多分类的问题(有限个结果);

回归问题的目标是预测一个连续值(实数 real number)(无限个结果);

以上分类也不是绝对,回归里面也可以有分类(例如:逻辑回归 Logistic regression和线性支持向量机 Linear support vector machine(线性SVM)),分类里面也可做回归(例如:KNN regression)

回归的理解

       要理解“回归”的概念,我们可以先看看它的历史。回归这个词最早是被高尔顿提出的,高尔顿这个人是谁呢,他是达尔文的表兄。他非常痴迷他兄长的进化论说,所以一直希望把进化论的理论应用到实证中,来证明不同人为什么会具有不同的特性。

高尔顿肖像

高尔顿在研究父母和子代身高关系时,观察得出的父母平均身高比子女平均身高矮一英寸,数据分布近似线性方程。他发现,在实际中,父母身高更高或更矮时,子女实际身高并不是比父母身高高一英寸,而是父母过矮的,子女比父母身高高不止一英寸,父母过高的,子女比父母身高还矮一点,也就是更接近平均身高。所以他认为自然界有一种约束力,使得身高的分布不会向高矮两个极端发展,而是趋于回到中心,所以称为回归

       他把这种趋势平均化的现象写到了自己1886年的论文中。论文的全名叫:Regression towards Mediocrity in Hereditary Stature. 这篇论文当年被发在了大不列颠以及爱尔兰人类研究学院期刊上。我们现今把论文中的这种“回归”现象称为:均值回归或者平庸回归(reversion to the mean/reversion to mediocrity)

我的理解是回归其实是“找规律”,在大量的数据中,找到这个数据集理论的值,即理论中X本来应该对应的Y;如下图所示,所有散点在不受干扰的情况,应该分布在直线上,“回归”数据本来的面目。

回归散点图

1.2 泛化、过拟合与欠拟合

泛化:如果一个模型能够对没见过的数据做出准确的预测,我们就说它能够从训练集泛化到测试集。

过拟合:在拟合模型的时候过分关注训练集的细节(噪音),得到一个在训练集上的表现很好,但是不能泛化到新数据上模型。

欠拟合:恰恰与过拟合相反,拟合模型的时候,在训练集的表现就很差了,模型过于简单。

通俗的讲就是

欠拟合:光看书不做题觉得自己会了,上了考场啥都不会。

过拟合: 做课后题全都能做对,上了考场还是啥都不会。

差不多的拟合: 做了题,背了老师给画了重点,考试60分过了。

优秀的拟合: 课后题全能作对,考试100分。

特征选择就是划重点。

1.3 监督学习算法

1.3.1 KNN(K-Nearest Neighbor)

KNN算法可以说是最简单的机器学习算法,构建模型只需要保存训练数据集即可。想要对新数据点做出预测,算法会在训练数据集中找到最近的数据点,也就是它的“最近邻”。

KNN分类:

1、选用Scikit-learn的鸢尾花数据集(load_iris),同时分割为属性值与目标值(target)的训练(占75%)和验证集(占25%),分别为X_train, X_test, y_train, y_test;

2、通过pandas进行描点,观察各个属性之间的关系,是否独立和可以进行分类;

3、通过观察点图(属性之间交叉)可以看到,利用花瓣和花萼的测量数据基本可以将三个目标值分开,使用KNeighborsClassifier进行训练、拟合;

4、通过KNN对象的score方法计算验证集的精度。得到的结果是0.9736842105263158≈0.97,也就是说,对于新的鸢尾花进行分类,可以认为我们模型预测有97%是正确的。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
import mglearn

#导入数据集
iris_dataset = load_iris()
#拆分数据集
X_train, X_test, y_train, y_test = train_test_split(iris_dataset['data'], iris_dataset['target'], random_state=0)
iris_dataframe = pd.DataFrame(X_train, columns=iris_dataset.feature_names)
#画出散点图
grr = pd.plotting.scatter_matrix(iris_dataframe, marker='o', figsize=(15, 15), c=y_train, hist_kwds={'bins': 20}, cmap=mglearn.cm3)
#设定1个近邻
knn = KNeighborsClassifier(n_neighbors=1)
#拟合验证集
knn.fit(X_train, y_train)
#测量模型精度
print(knn.score(X_test, y_test))

KNN的优点是简单,易于理解,易于实现,通常不用过多调节就可以得到不错的性能。但是训练集很大(特征数很多或者样本数很大),预测速度会比较慢,效果不是很好。

1.3.2 线性模型

入门视频可以参考:https://www.bilibili.com/video/av88480171?from=search&seid=2412839868211221294

入门文章求解线性模型参数:https://blog.csdn.net/sigtem/article/details/80546082

进阶学习可以参考:https://blog.csdn.net/devcloud/article/details/101102088

以上是学习线性模型的基础知识学习资料,已经有轮子了,直接用了,下面我想要说的是岭回归(ridge regression)和Lasso。

两者都采用了正则化的约束,使得模型更简单,以避免过拟合,泛化性能更好。

岭回归:对模型系数施加约束,使得系数(斜率)都接近于0,同时仍给出很好的预测结果。称为L2正则化。如果有足够多的训练数据,正则化变得不那么重要,并且岭回归和线性回归将具有相同的性能。如下图所示:波士顿房价数据集的学习曲线

                                                     图:岭回归和线性回归在波士顿房价数据集上的学习曲线

from mglearn import datasets
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split

X, y = datasets.make_wave(n_samples=200)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
#设置不同alpha
ridge1 = Ridge(alpha=0.1).fit(X_train, y_train)
ridge2 = Ridge(alpha=100).fit(X_train, y_train)
print(ridge1.score(X_train, y_train))
print(ridge1.score(X_test, y_test))
print(ridge2.score(X_train, y_train))
print(ridge2.score(X_test, y_test))

以上是观察不同alpha值(约束)对泛化性能的影响,增大alpha的值,约束会更强,会使得系数更加趋近于0,从而降低训练集性能,单可能会提高泛化性能。也可以通过改变样本n_samples的数量观察随着样本数量增加,alpha值影响的变化。

Lasso:对模型系数施加约束,使得系数(斜率)接近于0,不同的是,某些系数设定为0,说明某些特征被模型完全忽略,这可以看做是一种自动化的特征选择,留下了关键的影响因子。称为L1正则化。

在实践中,一般选择岭回归,但如果特征很多,且只有其中几个是重要的,那么选择Lasso可能更好。

1.3.3 决策树

一棵决策树包含 一个根节点,若干内部节点,若干叶子节点。可以理解为,每一个节点里面都存储着一定量的数据集,根节点最多,包含数据的全集,一个节点的数据集等于其所有子节点的集合。与此同时,根节点和内部节点都对应一个分类属性(分类的依据,就是 特征)。根节点到某一个子节点的那条路径,对应了一个判定测试序列。

站内有几篇文章可以参考:

【入门】【python和机器学习入门2】决策树2——决策树构建

【入门】随机森林简介

【进阶】决策树

随机森林

随机森林本质上是许多决策树的集合,其中每棵树都和其他树略有不同。随机森林背后的思想是,每棵树的预测可能都相对较好,但可能对部分数据过拟合。如果构造很多树,并且每棵树的预测都很好,单都以不同的方式过拟合,那么我们可以对这些书的结果取平均值来降低过拟合,既能减少过拟合,又能保持树的预测能力。

构造随机森林

随机森林构造过程中包含两个随机的过程:随机选择样本(有放回)、随机选择特征(无放回)

随机选择样本:从n个数据点中有放回地(即同一样本可以多次被抽取)重复随机抽取一个样本,共抽取n次。这样会创建一个与原数据集大小相同的数据集,但有些数据点会缺失(大约三分之一),而有些会重复。比如:我们想要对列表['a', 'b', 'c', 'd']随机采样,可能出现['b', 'd', 'd', 'c'],或者['d', 'a', 'b' ,'d']等等。

随机选择特征:在随机森林中,我们不像普通决策树一样计算所有特征的增益,而是从总量为M的特征向量中,随机选择m个特征,其中m可以等于sqrt(M),然后计算m个特征的增益,选择最优特征(属性)【注意,这里的随机选择特征是无放回的选择!】。如果我们设置m等于sqrt(M),即考虑数据集所有的特征,那么随机森林中的书将会十分相似;相反,如果m等于1,只取一个特征,划分时将无法选择对哪个特征进行测试,只能对随机选择的某个特征搜索不同的阈值。

由于随机森林采用了这两种随机采用,所构造的每棵决策树都是略有不同的。由于随机选择特征,每棵树中的每次划分都是基于特征的不同子集。

分析随机森林

下面我们将构造由5棵树组成的随机森林,代码如下:

from sklearn.datasets import make_moons
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from matplotlib import pylab
from mglearn import plots, discrete_scatter

X, y = make_moons(n_samples=100, noise=0.25, random_state=3)
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)
forest = RandomForestClassifier(n_estimators=5, random_state=2)
forest.fit(X_train, y_train)
#画图
fig, axes = pylab.subplots(2, 3, figsize=(20, 10))
for i, (ax, tree) in enumerate(zip(axes.ravel(), forest.estimators_)):
    ax.set_title("Tree {}".format(i))
    plots.plot_tree_partition(X_train, y_train, tree, ax=ax)
plots.plot_2d_separator(forest, X_train, fill=True, ax=axes[-1, -1], alpha=0.4)
axes[-1, -1].set_title("Random Forest")
discrete_scatter(X_train[:, 0], X_train[:, 1], y_train)
图:5棵随机化的决策树及其预测概率取平均后得到的​决策边界
图:5棵随机化的决策树及其预测概率取平均后得到的​决策边界

图中5棵随机化的决策树都有误差,因为随机选择样本,导致一些训练点没有包含在这些树中,随机森林比单独每一棵树的过拟合倒要小,给出的决策边界也更准确。在实际应用中,我们会用到更多的树,从而得到更平滑的边界。

梯度提升回归树(梯度提升机)

梯度提升回归树是通过合并多个决策树来构建一个更为强大的模型,虽然名字中含有“回归”,但这个模型即可以用于回归,也可以用于分类。与随机森林方法不同,梯度提升采用连续的方式构造树,每棵树都试图纠正前一棵树的错误。默认情况下,梯度提升回归树没有随机化,而是用到了强预剪枝。梯度提升树通常使用深度很小(1到5之间)的树,这样模型占用的内存更少,预测速度也更快。

用scikit-learn乳腺癌数据进行训练、拟合和测试集精度比较,代码如下,打印出结果分别为:

Accuracy gbrt1:0.965034965034965

Accuracy gbrt2:0.972027972027972

Accuracy gbrt3:0.972027972027972

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)
#默认最大深度是3
gbrt1 = GradientBoostingClassifier(random_state=0)
gbrt1.fit(X_train, y_train)
#设置最大深度为1
gbrt2 = GradientBoostingClassifier(random_state=0, max_depth=1)
gbrt2.fit(X_train, y_train)
#设置最大深度为2
gbrt3 = GradientBoostingClassifier(random_state=0, max_depth=2)
gbrt3.fit(X_train, y_train)
print('Accuracy gbrt1:{}'.format(gbrt1.score(X_test, y_test)))
print('Accuracy gbrt2:{}'.format(gbrt2.score(X_test, y_test)))
print('Accuracy gbrt3:{}'.format(gbrt3.score(X_test, y_test)))

梯度提升和随机森林两种方法在类似的数据上表现都很好,所以一般先尝试随机森林,如果随机森林效果很好,但预测时间太长,或者机器学习模型精度小数点后第二位的提高也很重要,那么切换成梯度提升会比较有效。

 


参考著作:

1、《Introduction to Machine Learning with Python》作者: Sarah Guido / Andreas C. Mueller 

2、知乎
链接:https://www.zhihu.com/question/30123729/answer/554278766

链接:https://www.zhihu.com/question/30123729/answer/555228865

链接:https://www.zhihu.com/question/32246256/answer/77697720

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值