线性模型用于分类, 分类的原理还要从公式说起.
线性模型的公司的结果 y 是一个连续的输出结果, 如果将 y 的值与 0 作一个界限上的区分, 那 y 的值将被分成两个区域. 公式的表达如下:
也就是说, 如果该公式 (函数) 预测的结果值小于 0, 就归类为 - 1, 如果结果值大于 0, 就归类为 1.
需要重点理解的地方在于:
对于用于回归的线性模型来说, 输出 y 是特征的线性函数, 是直线, 平面或超平面(对于更高维的数据集).
对于用于分类的线性模型, 决策边界是输入的线性函数.
不同线性模型算法之间的区别在于:
系数和截距的特定组合对训练集数据拟合好坏的度量方法;
是否使用正则化, 以及使用哪种正则化方法.
最觉的两种线性分类算法是 Logistic 回归和线性支持向量机. 前者在 linear_model.LogisticRegression 中实现, 后者在 svm.LinearSVC(SVC 代表支持再是分类器)中实现 .
接下来对这两个模型做一个初步认识吧!
- # 在学习之前, 先导入这些常用的模块
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- import mglearn
Logistic 与 LinearSVC 模型
下面, 将这两个模型用在二分类数据 forge 数据集上, 并显示模型得出的决策边界.
先展示下二分类的展示图:
- # 导入二分类数据
- X, y = mglearn.datasets.make_forge()
- mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
- plt.show()
- C:\Users\Administrator\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:77: DeprecationWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
- warnings.warn(msg, category=DeprecationWarning)
- # 导入 Logistic
- from sklearn.linear_model import LogisticRegression
- # 导入 LinearSVC
- from sklearn.svm import LinearSVC
- # 导入二分类数据
- X, y = mglearn.datasets.make_forge()
- # 建立一个幕布, 两个绘图区
- fig, axes = plt.subplots(1, 2, figsize=(10, 3))
- # 分别在两个绘图区上绘制两个模型的决策边界
- for model, ax in zip([LinearSVC(), LogisticRegression()], axes):
- # 在模型上训练数据
- clf = model.fit(X, y)
- # 绘制决策边界
- mglearn.plots.plot_2d_separator(clf, X, fill=False, eps=.5, ax=ax, alpha=.7)
- # 绘制二分类的训练数据
- mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
- # 设置标题为模型名称
- ax.set_title('{}'.format(clf.__class__.__name__))
- # 设置 x 坐标轴标签名称
- ax.set_xlabel('Feature 0')
- # 设置 y 坐标轴标签名称
- ax.set_ylabel('Feature 1')
- # 在第一个绘图区上显示图例
- axes[0].legend()
- plt.show()
说明:
forge 数据集有两个特征, 分别对应 X 轴与 Y 轴.
LinearSVC 与 LogisticRegression 得到的决策边界, 都是直线, 将数据分为了上下两个区域.
两个模型默认使用了 L2 正则化.
继续探讨:
对于 LinearSVC 与 LogisticRegression 而言, 决定正则化强度的权衡参数叫做 C.C 值越大, 对就的正则化越弱.
也就是说, 越大的 C 将拥有越上的约束力, 即系数的大小更自由, 模型对于数据的贴合度将变得更复杂.
如果 C 越小, 则对系数的约束越大, 甚至趋向于 0, 使模型更能贴合大多数数据, 模型也更简单.
下面直接展示一下 LinearSVC 模型的 C 分别取 0.01,1,100 时模型的决策边界效果:
mglearn.plots.plot_linear_svc_regularization()
对上图的总结:
最左侧的图, C 值很小, 所以对应强正则化. 要求模型更贴合于大多数数据, 因此对于图中两个错误的点进行了忽略.
中间的图, C 值稍大, 由于对模型的约束变小, 模型对于数据的反应则变得更加第三一些, 决策线向着两个错误的点进行偏移, 希望更好的贴合训练数据.
右侧图 C 值很大, 因为对模型的约束很小, 导致模型的决策边界要求对所有数据都贴合, 造成了过拟合现象.
再来看看使用乳腺癌数据集对 LogisticRegression 模型做出分析:
- # 导入乳腺癌数据
- from sklearn.datasets import load_breast_cancer
- cancer = load_breast_cancer()
- # 将数据分为训练集测试集
- from sklearn.model_selection import train_test_split
- X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)
- # 使用模型训练数据
- logreg = LogisticRegression().fit(X_train, y_train)
- # 查看模型的评估值
- print('训练集评估分数:', logreg.score(X_train, y_train))
- print('测试集评估分数:', logreg.score(X_test, y_test))
训练集评估分数: 0.9553990610328639
测试集评估分数: 0.958041958041958
这里模型置信的 C 值是 1. 如果训练集的评分与测试集的评分差不多, 那可能存在欠拟合的现象.
现在给模型增大 C 值, 再看看评估结果:
- logreg100 = LogisticRegression(C=100).fit(X_train, y_train)
- print('训练集评估分数:', logreg100.score(X_train, y_train))
- print('测试集评估分数:', logreg100.score(X_test, y_test))
训练集评估分数: 0.971830985915493
测试集评估分数: 0.965034965034965
通过增大模型的 C 值, 发现模型的精度变高了.
现在再减小 C 值看看模型的评估分数:
- logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train)
- print('训练集评估分数:', logreg001.score(X_train, y_train))
- print('测试集评估分数:', logreg001.score(X_test, y_test))
训练集评估分数: 0.9342723004694836
测试集评估分数: 0.9300699300699301
可以看出, 模型的精度变小了, 并且存在欠拟合的可能.
按照老办法, 我们当不同 C 值情况下, 模型得出的系数图例化, 看看结果:
- plt.plot(logreg.coef_.T, 'o', label='C=1')
- plt.plot(logreg100.coef_.T, '^', label='C=100')
- plt.plot(logreg001.coef_.T, 'v', label='C=0.01')
- plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
- plt.hlines(0, 0, cancer.data.shape[1])
- plt.ylim(-5, 5)
- plt.xlabel('Codefficient index')
- plt.ylabel('Coefficient magnitude')
- plt.legend()
- plt.show()
从这个图例可以看出, C 值越小, 模型的系数就越趋向于 0.
另外, 该模型默认使用 L2 正则, 也可以将其改成 L1 正则, 以减少模型使用的特征:
- # 评估
- for C, marker in zip([0.001, 1, 100], ['o', '^', 'v']):
- lr_l1 = LogisticRegression(C=C, penalty='l1').fit(X_train, y_train)
- print('训练集, C={0}, 评估分数 ={1}'.format(C, lr_l1.score(X_train, y_train)))
- print('测试集, C={0}, 评估分数 ={1}'.format(C, lr_l1.score(X_test, y_test)))
- # 绘图
- plt.plot(lr_l1.coef_.T, marker, label='C={}'.format(C))
- plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
- plt.hlines(0, 0, cancer.data.shape[1])
- plt.ylim(-5, 5)
- plt.xlabel('Codefficient index')
- plt.ylabel('Coefficient magnitude')
- plt.legend(loc=3)
- plt.show()
训练集, C=0.001, 评估分数 = 0.9131455399061033
测试集, C=0.001, 评估分数 = 0.9230769230769231
训练集, C=1, 评估分数 = 0.960093896713615
测试集, C=1, 评估分数 = 0.958041958041958
训练集, C=100, 评估分数 = 0.9859154929577465
测试集, C=100, 评估分数 = 0.9790209790209791
Ok, 上图对于不同 C 值所对应的 L 正则下的系数分布有了直观的了解, 也就明白了对应的约束力.
这里主要需要明白设置 L1 或 L2 需要通过参数 penalty 来设置.
用于多分类的线性模型
多分类其实也是一处二分类的模式, 它是一对其余的方法.
这里展示一个三类的 gf 数据:
- from sklearn.datasets import make_blobs
- X, y = make_blobs(random_state=42)
- mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
- plt.xlabel('Feature 0')
- plt.ylabel('Feature 1')
- plt.legend(['Class 0', 'Class 1', 'Class 2'])
- plt.show()
然后使用该数据对 LinearSVC 分类器进行训练:
- linear_svm = LinearSVC().fit(X, y)
- print('模型斜率集:', linear_svm.coef_.shape)
- print('模型截距集:', linear_svm.intercept_.shape)
模型斜率集: (3, 2)
模型截距集: (3,)
通过形状可以明白: 斜率集有 3 行, 每行代表类别之一的一个系数向量; 有 2 列, 每列包含某个特征对应的系数值. 而截距是个一维数据, 包含每个类别的截距值.
现在将分类器给出的直线进行可视化:
- mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
- line = np.linspace(-15, 15)
- for coef, intercept, color in zip(linear_svm.coef_, linear_svm.intercept_, ['b', 'r', 'g']):
- plt.plot(line, -(line * coef[0] + intercept) / coef[1], c=color)
- plt.ylim(-10, 15)
- plt.xlim(-10, 8)
- plt.xlabel('Feature 0')
- plt.ylabel('Feature 1')
- plt.legend(['Class 0', 'Class 1', 'Class 2'], loc=(1.01, 0.3))
- plt.show()
在这里, 线条的颜色与各点的颜色是一致的. 从图中可以很直观的看到这三个点是如何被分成三类的.
但是, 这三条线交叉的地方, 有一个空白的三角区, 那这个区域属于哪个类别呢?
答案是分类方程结果最大的那个类别, 即最接近的那条结对应的类别!
下面将展示整个二维空间是如何被分类的:
- mglearn.plots.plot_2d_classification(linear_svm, X, alpha=.7)
- mglearn.discrete_scatter(X[:, 0], X[:, 1], y)
- line = np.linspace(-15, 15)
- for coef, intercept, color in zip(linear_svm.coef_, linear_svm.intercept_, ['b', 'r', 'g']):
- plt.plot(line, -(line * coef[0] + intercept) / coef[1], c=color)
- plt.xlabel('Feature 0')
- plt.ylabel('Feature 1')
- plt.legend(['Class 0', 'Class 1', 'Class 2'], loc=(1.01, 0.3))
- plt.show()
通过上图很明白的就看出中间的三角区是如何被分类的了!
好吧, 到现在, 机器学习的基础模型的探讨就告一段落了. 不过, 这些模型并不常用, 在接下来, 将着重学习朴素贝叶期斯分类器, 决策树, 核支持向量机, 神经网络等经典模型!
来源: http://www.jianshu.com/p/80e84987f4b5