【机器学习】用于分类的线性模型:Logistic回归与线性支持向量机

5787343-30f35f3c31e0449d.jpg

线性模型用于分类,分类的原理还要从公式说起。

线性模型的公司的结果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)
5787343-5fa81d6958c2e19d.png
# 导入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()
5787343-742816b9fee5657e.png

说明:

  • forge数据集有两个特征,分别对应X轴与Y轴。
  • LinearSVC与LogisticRegression得到的决策边界,都是直线,将数据分为了上下两个区域。
  • 两个模型默认使用了L2正则化。

继续探讨:

  • 对于LinearSVC与LogisticRegression而言,决定正则化强度的权衡参数叫做CC值越大,对就的正则化越弱
  • 也就是说,越大的C将拥有越上的约束力,即系数的大小更自由,模型对于数据的贴合度将变得更复杂。
  • 如果C越小,则对系数的约束越大,甚至趋向于0,使模型更能贴合大多数数据,模型也更简单。

下面直接展示一下LinearSVC模型的C分别取0.011100时模型的决策边界效果:

mglearn.plots.plot_linear_svc_regularization()
5787343-fed562cbcbbcd23e.png

对上图的总结:

  1. 最左侧的图,C值很小,所以对应强正则化。要求模型更贴合于大多数数据,因此对于图中两个错误的点进行了忽略。
  2. 中间的图,C值稍大,由于对模型的约束变小,模型对于数据的反应则变得更加第三一些,决策线向着两个错误的点进行偏移,希望更好的贴合训练数据。
  3. 右侧图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()
5787343-d3746920534af4d2.png

从这个图例可以看出,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
5787343-ffd93333677d2ed9.png

Ok,上图对于不同C值所对应的L正则下的系数分布有了直观的了解,也就明白了对应的约束力。

这里主要需要明白设置L1L2需要通过参数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()
5787343-ceeb7cd87f9a2655.png

然后使用该数据对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()
5787343-5c7e8ba29af1d512.png

在这里,线条的颜色与各点的颜色是一致的。从图中可以很直观的看到这三个点是如何被分成三类的。

但是,这三条线交叉的地方,有一个空白的三角区,那这个区域属于哪个类别呢?

答案是分类方程结果最大的那个类别,即最接近的那条结对应的类别!

下面将展示整个二维空间是如何被分类的:

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()
5787343-a41febbdb4de802f.png

通过上图很明白的就看出中间的三角区是如何被分类的了!

好吧,到现在,机器学习的基础模型的探讨就告一段落了。不过,这些模型并不常用,在接下来,将着重学习朴素贝叶期斯分类器、决策树、核支持向量机、神经网络等经典模型!

5787343-77445b09eb2b16a6.gif

猜你喜欢

转载自blog.csdn.net/weixin_34082177/article/details/86806834
今日推荐