Machine Learning-教你用Scikit-Learn来做分类器(上)

2019-08-22 13:32:07 浏览数 (1)

机器学习系列专栏

选自 Python-Machine-Learning-Book On GitHub

作者:Sebastian Raschka

翻译&整理 By Sam

相信接触机器学习的同学对于Scikit-Learn肯定不会陌生,而自己亲手去使用它来构建自己的分类器应该不多,今天这篇文章就简单地整理一些干货,帮助大家快速上手构建一个分类器,嘻嘻!

由于文章篇幅较长,还是先把本文的结构贴在前面,如下:

上篇:

  • Scikit-Learn初认识
    • 使用Scikit-Learn训练感知器
  • 使用逻辑回归构建一个概率类的分类模型
    • 逻辑回归的激活函数
    • 逻辑回归的损失函数
    • 使用sklearn训练一个逻辑回归模型
    • 使用正则化处理过拟合

下篇:

  • 使用Kernel-SVM来解决非线性问题
    • 利用核技巧在高维空间中寻找分离超平面
  • 机器学习决策树模型
    • 最大化信息增益-获得最大的提升度
    • 建立决策树
    • 通过随机森林将“弱者”与“强者”模型集成
  • K近邻分类模型(一个懒惰的算法)
  • 参考文献

PS:代码已单独保存:可在公众号后台输入“sklearn”进行获取ipynb文件

Scikit-Learn初认识

关于Scikit的介绍,大家应该看过很多了,简答来说它就是用Python开发的机器学习库,其中包含大量机器学习算法、数据集,是数据挖掘方便的工具,更多的介绍这里就不说了,大家有兴趣可以去百度一下呗。

我们直接从scikit-learn里加载iris数据集。在这里,第三列表示花瓣长度,第四列表示花瓣宽度。这些类已经转换为整数标签,其中0=Iris-Setosa, 1=Iris-Versicolor, 2=Iris-Virginica。

使用Scikit-Learn训练感知器

导入数据集:

代码语言:javascript复制
1# 导入sklearn里面的iris数据集,并且获取特征和目标列
2from sklearn import datasets
3import numpy as np
4iris = datasets.load_iris()
5X = iris.data[:, [2, 3]]
6y = iris.target

划分数据集:

代码语言:javascript复制
1# 根据sklearn的版本使用不同的类
2if Version(sklearn_version) < '0.18':
3    from sklearn.cross_validation import train_test_split
4else:
5    from sklearn.model_selection import train_test_split
6X_train, X_test, y_train, y_test = train_test_split(
7    X, y, test_size=0.3, random_state=0)

特征标准化:

代码语言:javascript复制
1from sklearn.preprocessing import StandardScaler
2sc = StandardScaler()
3sc.fit(X_train)
4X_train_std = sc.transform(X_train)
5X_test_std = sc.transform(X_test)

训练模型:

代码语言:javascript复制
1from sklearn.linear_model import Perceptron
2ppn = Perceptron(n_iter=40, eta0=0.1, random_state=0)
3ppn.fit(X_train_std, y_train)

模型效果:

代码语言:javascript复制
1y_pred = ppn.predict(X_test_std)
2print('错误分类的样本数: %d' % (y_test != y_pred).sum()   '个')
3from sklearn.metrics import accuracy_score
4print('准确度: %.2f' % accuracy_score(y_test, y_pred))
代码语言:javascript复制
output:
错误分类的样本数: 4个
准确度: 0.91

绘制分类情况:

代码语言:javascript复制
 1from matplotlib.colors import ListedColormap
 2import matplotlib.pyplot as plt
 3import warnings
 4def versiontuple(v):
 5    return tuple(map(int, (v.split("."))))
 6def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
 7    # setup marker generator and color map
 8    markers = ('s', 'x', 'o', '^', 'v')
 9    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
10    cmap = ListedColormap(colors[:len(np.unique(y))])
11    # plot the decision surface
12    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max()   1
13    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max()   1
14    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
15                           np.arange(x2_min, x2_max, resolution))
16    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
17    Z = Z.reshape(xx1.shape)
18    plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
19    plt.xlim(xx1.min(), xx1.max())
20    plt.ylim(xx2.min(), xx2.max())
21    for idx, cl in enumerate(np.unique(y)):
22        plt.scatter(x=X[y == cl, 0], 
23                    y=X[y == cl, 1],
24                    alpha=0.6, 
25                    c=cmap(idx),
26                    edgecolor='black',
27                    marker=markers[idx], 
28                    label=cl)
29    # highlight test samples
30    if test_idx:
31        # plot all samples
32        if not versiontuple(np.__version__) >= versiontuple('1.9.0'):
33            X_test, y_test = X[list(test_idx), :], y[list(test_idx)]
34            warnings.warn('Please update to NumPy 1.9.0 or newer')
35        else:
36            X_test, y_test = X[test_idx, :], y[test_idx]
37        plt.scatter(X_test[:, 0],
38                    X_test[:, 1],
39                    c='',
40                    alpha=1.0,
41                    edgecolor='black',
42                    linewidths=1,
43                    marker='o',
44                    s=55, label='test set')

再次训练模型并可视化:

代码语言:javascript复制
 1# 为了显示中文(这里是Mac的解决方法,其他的大家可以去百度一下)
 2from matplotlib.font_manager import FontProperties
 3font = FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
 4# vstack:纵向合并,更多具体用法可以百度
 5# hstack:横行合并,更多具体用法可以百度
 6X_combined_std = np.vstack((X_train_std, X_test_std))
 7y_combined = np.hstack((y_train, y_test))
 8plot_decision_regions(X=X_combined_std, y=y_combined,
 9                      classifier=ppn, test_idx=range(105, 150))
10plt.xlabel('花瓣长度 [标准化后]',FontProperties=font,fontsize=14)
11plt.ylabel('花瓣宽度 [标准化后]',FontProperties=font,fontsize=14)
12plt.legend(loc='upper left')
13plt.tight_layout()
14plt.show()

output:

使用逻辑回归构建一个概率类的分类模型

逻辑回归的激活函数

关于激活函数,首先要搞清楚的问题是,激活函数是什么,有什么用?不用激活函数可不可以?答案是不可以。

激活函数的主要作用是提供网络的非线性建模能力。如果没有激活函数,那么该网络仅能够表达线性映射,此时即便有再多的隐藏层,其整个网络跟单层神经网络也是等价的。因此也可以认为,只有加入了激活函数之后,深度神经网络才具备了分层的非线性映射学习能力。

激活函数的性质:

  • 可微性:当优化方法是基于梯度的时候,这个性质是必须的。
  • 单调性:当激活函数是单调的时候,单层网络能够保证是凸函数。
  • 输出值的范围:当激活函数输出值是 有限 的时候,基于梯度的优化方法会更加稳定,因为特征的表示受有限权值的影响更显著;当激活函数的输出是 无限 的时候,模型的训练会更加高效,不过在这种情况小,一般需要更小的learning rate

Sigmoid 是使用范围最广的一类激活函数,具有指数函数形状,它在物理意义上最为接近生物神经元。此外,(0, 1) 的输出还可以被表示作概率,或用于输入的归一化,代表性的如Sigmoid交叉熵损失函数。(一般会用于二分类问题的激活函数,深度学习大概还有3种激活函数,大家可以去百度一下。)

图:sigmoid函数长酱紫

逻辑回归的损失函数

逻辑回归的对数似然损失函数cost function:

图:详见参考文献[2]

也可以直观地从图里看到损失函数的原理:

使用sklearn训练一个逻辑回归模型

关于逻辑回归算法,调用的方式和上面的ppn算法是类似,如下:

代码语言:javascript复制
 1from sklearn.linear_model import LogisticRegression
 2# 导入逻辑回归算法包
 3lr = LogisticRegression(C=1000.0, random_state=0)
 4lr.fit(X_train_std, y_train)
 5plot_decision_regions(X_combined_std, y_combined,
 6                      classifier=lr, test_idx=range(105, 150))
 7plt.xlabel('花瓣长度 [标准化后]',FontProperties=font,fontsize=14)
 8plt.ylabel('花瓣宽度 [标准化后]',FontProperties=font,fontsize=14)
 9plt.legend(loc='upper left')
10plt.tight_layout()
11plt.show()

output:

使用正则化处理过拟合

关于过拟合的概念这里就不做过多的解释了,大概就是如下图一样(从左至右分别是欠拟合-正常-过拟合)。

正则化是用来降低overfitting(过拟合)的,对于数据集梳理有限的情况下,防止过拟合的一种方式就是降低模型的复杂度,怎么降低?一种方式就是在cost函数中加入正则化项,正则化项可以理解为复杂度,cost越小越好,但cost加上正则项之后,为了使cost小,就不能让正则项变大,也就是不能让模型更复杂,这样就降低了模型复杂度,也就降低了过拟合。这就是正则化。正则化也有很多种,常见为两种L2和L1。

(机器学学习中的正则化相关的内容可以参见李航的书:《统计学习方法》)

简单来说,越是复杂的模型,对于数据的表达能力就越强,就更加容易出现过度拟合的情况,所以正则化就是通过来降低模型复杂度从而达到模型泛化能力的提升,也就是处理过拟合。

PS:代码已单独保存:可在公众号后台输入“sklearn”进行获取ipynb文件

参考文献

1. 深度学习笔记(三):激活函数和损失函数

https://blog.csdn.net/u014595019/article/details/52562159

2. logistic回归详解(二):损失函数(cost function)详解

https://blog.csdn.net/bitcarmanlee/article/details/51165444?locationNum=2&fps=1

3. 为什么说regularization是缓解overfitting的好办法?

https://www.zhihu.com/question/274502949/answer/376629836

4. 最优化方法:L1和L2正则化regularization

https://blog.csdn.net/pipisorry/article/details/52108040

5. 数据预处理中归一化(Normalization)与损失函数中正则化(Regularization)解惑

https://www.cnblogs.com/arachis/p/Regulazation.html?utm_source=itdadao&utm_medium=referral

代码语言:javascript复制

嘻嘻,看到这里,上面的歌应该听完了,再来一首~

代码语言:javascript复制
—End—

0 人点赞