线性模型

技术分享4年前 (2020)更新 技术分享
2,082 0 0
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
from sklearn.model_selection import train_test_split

1.用于回归的线性模型

对于回归问题,线性模型预测的一般公式如下:

y = w[0]x[0]+w[1]x[1]+…+w[p]*x[p]+b

这里x[0]到x[p]表示单个数据点的特征(本例中特征个数为p+1),w和b是学习模型的参数,yᨈ是模型的预测结果。对于单一特征的数据集,公式如下:

y = w[0]*x[0]+b

这就是高中数学里的直线方程。这里w[0]是斜率,b是y轴偏移。对于有更多特征的数据集,w包含沿沿每个特征坐标轴的斜率。也可以将预测的响应值看作输入特征的加权求和,权重由w的元素给出(可以取负值)。

下列代码可以在一维wave数据集上学习参数w[0]和b

mglearn.plots.plot_linear_regression_wave()
w[0]: 0.393906  b: -0.031804

线性模型

用于回归的线性模型可以表示为这样的回归模型:对单一特征的预测结果是一条直线,两个特征时是一个平面,或者在更高维度(即更多特征)时是一个超平面

如果将直线的预测结果与线性模型 的预测结果相比较,会发现直线的预测能力非常受限。似乎数据的所有细节都丢失了。从某种意义上讲,这种说法是正确的。假设目标y是特征的线性组合,这是一个非常强(也有点不现实的)假设。但观察一维数据得出的观点有些片面。对于有多个特征的数据集而言,线性模型可以非常强大。特别地,如何特征数量大于训练数据点的数量,任何目标y都可以在(训练集上)用线性函数完美拟合。

2.线性回归(普通最小二乘法)

线性回归,或者普通最小二乘法(ordinary least squares,OLS),是回归问题最简单也最经典的线性方法。线性回归寻找参数w和b,使得对训练集的预测值与真实的目标值y之间的均方误差最小。均方误差(mean squared error)是预测值与真实值之差的平方和除以样本数。线性回归没有参数,这是一个优点,但也因此无法控制模型的复杂度。

下列代码构建一个线性模型

from sklearn.linear_model import LinearRegression
X, y = mglearn.datasets.make_wave(n_samples=60)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

lr = LinearRegression().fit(X_train, y_train)

“斜率”参数(w,也叫作权重或系数)被保存在coef_属性中,而偏移或截距(b)被保存在intercept_属性中:

print("lr_coef_: {}".format(lr.coef_))
print("lr_intercept_: {}".format(lr.intercept_))
lr_coef_: [0.39390555]
lr_intercept_: -0.031804343026759746

intercept_属性是一个浮点数,而coef_属性是一个NumPy数组,每个元素对应一个输入特征。由于wave数据集中只有一个输入特征,所以lr.coef_中只有一个元素

检测一下训练集和测试集的性能:

print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))
Training set score: 0.67
Test set score: 0.66

R^2约为0.66,这个结果不是很好,但我们注意到,训练集和测试集上的分数非常接近。这说明可能存在欠拟合,而不是过拟合。对于一个一维数据集来说,过拟合的风险很小,因为模型非常简单(或受限)。然而,对于更高维的数据集(即有大量特征的数据集),线性模型将变得更加强大,过拟合的可能性也会变大。我们来看一下LinearRegression在更复杂的数据集上的表现,比如波士顿房价数据集。这个数据集有506个样本和105个导出特征。

X, y = mglearn.datasets.load_extended_boston()

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
lr = LinearRegression().fit(X_train, y_train)

比较一下训练集和测试集的分数可以发现,在训练集上的预测结果非常准确,但测试集上的R^2要低很多:

print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))
Training set score: 0.95
Test set score: 0.61

训练集和测试集之间的性能差异是过拟合的明显标志,因此我们应该试图找到一个可以控制复杂度的模型。标准线性回归最常用的替代方法之一就是岭回归(ridge regression)

3.岭回归

岭回归也是一种用于回归的线性模型,因此它的预测公式与普通最小二乘法相同。但在岭回归中,对系数(w)的选择不仅要在训练数据上得到好的预测结果,而且还要拟合附加约束。我们还希望系数尽量小,换句话说,w的所有元素都应该接近于0。直观上来看,这意味着每个特征对输出的影响尽可能小(即斜率很小),同时仍给出很好的预测结果,这种约束是所谓正则化(regularization)的一个例子。正则化是指对模型做显式约束,以避免过拟合。岭回归用到的这种被称为L2正则化

从数学的观点来看,Ridge惩罚了系数的L2范数或w的欧式长度。

岭回归在linear_model.Ridge中实现。

from sklearn.linear_model import Ridge

ridge = Ridge().fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge.score(X_test, y_test)))
Training set score: 0.89
Test set score: 0.75

可以看出,Ridge在训练集上的分数要低于LinearRegression,但在测试集上的分数 更高 。这和我们的预期一致。线性回归对数据存在过拟合。Ridge是一种约束更强的模型,所以更不容易过拟合。复杂度更小的模型意味着在训练集上的性能更差,但泛化性能更好。由于我们只对泛化性能感兴趣,所以应该选择Ridge模型而不是LinearRegression模型。

Ridge模型在模型的简单性(系数都接近于0)与训练集性能之间做出权衡。简单性和训练集性能二者对于模型的重要程度可以通过设置alpha参数来指定。在前面的例子中,我们用的是默认参数alpha=1.0,但没有理由认为这会给出最佳权衡。alpha的最佳设定值取决于具体数据集。增大alpha会使得系数更加趋向于0,从而降低训练集性能,但可能会提高泛化性能。例如:

ridge10 = Ridge(alpha=10).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge10.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge10.score(X_test, y_test)))
Training set score: 0.79
Test set score: 0.64

减小alpha可以让系数受到的限制更小,对于非常小的alpha值,系数几乎没有受到限制,我们得到一个与LinearRegression类似的模型:

ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge01.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge01.score(X_test, y_test)))
Training set score: 0.93
Test set score: 0.77

可以查看alpha取不同值时模型的coef_属性,从而更加定性的理解alpha参数是如何改变模型的。更大的alpha表示约束更强的模型,所以我预计大alpha对应的coef_元素比小alpha对应的coef_元素要小。

plt.plot(ridge.coef_, 's', label='Ridge alpha=1')
plt.plot(ridge10.coef_, '^', label='Ridge alpha=10')
plt.plot(ridge01.coef_, 'v', label='Ridge alpha=0.1')

plt.plot(lr.coef_, 'o', label='LinearRegression')
plt.xlabel('Coefficient index')
plt.ylabel('Coefficient magnitude')
plt.hlines(0, 0, len(lr.coef_))
plt.ylim(-25, 25)
plt.legend()

线性模型

x轴对应coef_的元素:x=0对应第一个特征的系数,x=1对应第二个特征的系数,以此类推,一直到x=100。y轴表示该系数的具体数值。对于alpha=10,系数大多在-3到3之间。对于alpha=1的ridge模型,系数稍大一些。对于alpha=0.1,点的范围更大。对于没有做正则化的线性回归(即alpha=0),点的范围更大,许多点超出了图像的范围。

还有一种方法可以用来理解正则化的影响,就是固定alpha值,但改变训练数据量。对波士顿房价数据集做二次抽样,并在数据量逐渐增加的数据集上分别对LinearRegression和Ridge(alpha=1)两个模型进行评估(将模型大小作为数据集大小的函数进行绘图,这样的图像叫作学习曲线):

mglearn.plots.plot_ridge_n_samples()

线性模型

如上图所示,无论是岭回归还是线性回归,所有数据集大小对应的训练分数都要高于测试分数。由于岭回归是正则化的,因此它的训练分数要整体低于线性回归的训练分数。但岭回归的测试分数要更高,特别是对较小的子数据集。如果少于400个数据点,线性模型学不到任何内容。随着模型可用的数据越来越多,两个模型的测试集性能开始提升,最终线性模型的性能追上了岭回归。这里要注意的是,如果有足够多的训练数据,正则化变得不那么重要,并且岭回归和线性回归具有相同的测试集性能。从图中还可以看出线性回归的训练性能在下降。如果添加更多数据,模型将更加难以过拟合或记住所有的数据。

4. lasso

除了Ridge,还有一种正则化的线性回归是Lasso。与岭回归相同,使用Lasso也是约束系数使其接近于0,但用到的方法不同,叫作L1正则化。L1正则化的结果是,使用Lasso时某些系数刚好为0。这说明某些特征被模型完全忽略。这可以看作是一种自动化的特征选择。某些系数刚好为0,这样模型更容易解释,也可以呈现模型最重要的特征。

Lasso惩罚系数向量的L1范数,换句话说,系数的绝对值之和

将Lasso应用在拓展的波士顿房价数据集上:

from sklearn.linear_model import Lasso

lasso = Lasso().fit(X_train, y_train)
print("Training set score: {:.2f}".format(lasso.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso.score(X_test, y_test)))
print("Numbor of feayures used: {}".format(np.count_nonzero(lasso.coef_)))
Training set score: 0.29
Test set score: 0.21
Numbor of feayures used: 4

可以看出,Lasso在训练集与测试集上的表现都很差。这表示存在欠拟合,我们发现模型只用到了105个特征中的4个。与Ridge类似,Lasso也有一个正则化参数alpha,可以控制系数趋向于0的强度。Lasso()类中默认值alpha=1。为了降低欠拟合,我们尝试减小alpha。这么做的同时,我们还需要增加max_iter的值(运行迭代的最大次数):

# 我们增大max_iter的值,否则模型会警告我们,说应该增大max_iter
lasso001 = Lasso(alpha=0.01, max_iter=100000).fit(X_train, y_train)

print("Training set score: {:.2f}".format(lasso001.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso001.score(X_test, y_test)))
print("Numbor of feayures used: {}".format(np.count_nonzero(lasso001.coef_)))
Training set score: 0.90
Test set score: 0.77
Numbor of feayures used: 33

alpha值变小,我们可以拟合一个更复杂的模型,在训练集和测试集上的表现也更好。模型性能比使用Ridge时略好一点,而且我们只用到了105个特征中的33个。

但如果把alpha设得太小,就会消除正则化的效果,并出现过拟合,得到与LinearRegression类似的结果:

lasso00001 = Lasso(alpha=0.0001, max_iter=100000).fit(X_train, y_train)

print("Training set score: {:.2f}".format(lasso00001.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso00001.score(X_test, y_test)))
print("Numbor of feayures used: {}".format(np.count_nonzero(lasso00001.coef_)))
Training set score: 0.95
Test set score: 0.64
Numbor of feayures used: 94

对不同系数的模型进行作图

plt.plot(lasso.coef_, 's', label='Lasso alpha=1')
plt.plot(lasso001.coef_, '^', label='Lasso alpha=0.01')
plt.plot(lasso00001.coef_, 'v', label='Lasso alpha=0.0001')

plt.plot(ridge01.coef_, 'o', label='Ridge alpha=0.1')
plt.legend(ncol=2, loc=(0, 1.05))
plt.ylim(-25, 25)
plt.xlabel('Coefficient index')
plt.ylabel('Coefficient magnitude')
Text(0,0.5,'Coefficient magnitude')

线性模型

在alpha=1时,Lasso回归不仅大部分系数为0,而且其他系数也都很小。将alpha减小至0.01,我们得到图中向上的三角形,大部分特征等于0,alpha=0.0001时,我们得到正则化很弱的模型,大部分系数都不为0,并且还很大。为了便于比较,图中用圆形表示Ridge的最佳结果。alpha=0.1的Ridge模型的预测性能与alpha=0.01的Lasso模型类似,但Ridge模型的所有系数都不为0.

在实践中,两个正则化模型首选岭回归。但如果特征很多,你认为只有其中几个是重要的,那么选择Lasso可能更好。同样,如果你想要一个容易解释的模型,Lasso可以给出更容易理解的模型,因为它只选择了一部分输入特征。scikit-learn还提供了ElasticNet类,结合了Lasso和Ridge的惩罚项。在实践中,这种结合的效果最好,不过代价是要调节两个参数,一个用于L1正则化,一个用于L2正则化。

5. 用于分类的线性模型

线性模型也广泛用于分类问题。我们首先来看二分类。这时可以利用下面的公式进行预测:

y = w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b > 0

看起来与线性回归的公式非常相似,但我们没有返回特征的加权求和,而是为预测设置了阈值(0)。如果函数值小于0,我们就预测类别-1,如果函数值大于0,我们就预测类别+1。对于所有用于分类的线性模型,这个预测规则都是通用的。同样,有很多种不同的方法来找出系数(w)和截距(b)。

对于用于回归的线性模型,输出y是特征的线性函数,是直线、平面或超平面。对于用于分类的线性模型,决策边界是输入的线性函数。换句话说,(二元)线性分类器是利用直线、平面或超平面来分开两个类别的分类器。

学习线性模型有很多种算法。这些算法的区别在于以下两点:

  • 系数和截距的特定组合对训练数据拟合好坏的度量方法;
  • 是否使用正则化,以及使用哪种正则化方法。

不同的算法使用不同的方法来度量“对训练集拟合好坏”。由于数学上的技术原因,不可能调节w和b使得算法产生的误分类最少。对于我们的目的,以及许多应用而言,上面第一点(称为损失函数)的选择并不重要。

最常见的两种线性分类算法是Logistic 回归(logistic regression)和线性支持向量机(linear support vector machine,简称SVM),前者在linear_model.LogisticRegression中实现,后者在svm.LinearSVC(SVC代表支持向量分类器)中实现。

下列代码将LogisticRegression和LinearSVC模型应用到forge数据集上,并将线性模型找到的决策边界可视化:

from sklearn.linear_model import LogisticRegression
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=0.5, ax=ax, alpha=.7)
    mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
    ax.set_title("{}".format(clf.__class__.__name__))
    ax.set_xlabel("Feature 0")
    ax.set_ylabel("Feature 1")
axes[0].legend()

线性模型

在上图中,forge数据集的第一个特征位于x轴,第二个特征位于y轴,图中分别展示了LinearSVC和LogisticRegression得到的决策边界,都是直线,将顶部归为类别1的区域与底部归为类别0的区域分开了。

两个模型得到了相似的决策边界。两个模型中都有两个点是分类错误的,默认使用L2正则化。

对于LogisticRegression和LinearSVC,决定正则化强度的权衡参数叫作C。C值越大,对应的正则化越弱。
参数C的还有一个作用:较小的C值可以让算法尽量适应“大多数”数据点,而较大的C值更强调每个数据点都分类正确的准确性。下面使用LinearSVC的图示:

mglearn.plots.plot_linear_svc_regularization()

线性模型

在左侧的图中,C值很小,对应强正则化。大部分属于类别0的点位于底部,大部分属于类别1的点位于顶部。强正则化项的模型会选择一条相对水平的线,有两个点分类错误。中间图C值稍大,模型更关注两个分类错误的样本,使决策边界的斜率的绝对值变大。最后,在右侧的图中,模型的C值非常大,使得决策边界斜率的绝对值也很大,对类别0的所有点都分类正确。类别1仍有一个点分类错误,这是因为对整个数据集来说,不可能用一条直线将所有点正确分类。右侧图中的模型尽可能使所有点的分类都正确,但可能无法学习到类别的整体分布。(很可能过拟合)

与回归的情况类似,用于分类的线性模型在低维空间看起来非常受限,决策边界只能是直线或平面。同样,在高维空间中,用于分类的线性模型变得非常强大,当考虑更多特征时,避免过拟合变得越来越重要。

下面代码使用乳腺癌数据集详细分析LogisticRegression:

from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
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("Training set socre: {:.3f}".format(logreg.score(X_train, y_train)))
print("Test set socre: {:.3f}".format(logreg.score(X_test, y_test)))
Training set socre: 0.955
Test set socre: 0.958

C=1时的默认值给出了相当好的性能,在训练接和测试集都达到了近96%的精度。但由于训练接和测试集的性能非常接近,所以模型很可能是欠拟合的。我们尝试增大C来拟合一个更复杂的模型:

logreg100 = LogisticRegression(C=100).fit(X_train, y_train)
print("Training set socre: {:.3f}".format(logreg100.score(X_train, y_train)))
print("Test set socre: {:.3f}".format(logreg100.score(X_test, y_test)))
Training set socre: 0.972
Test set socre: 0.965

使用C=100可以得到更高的训练集精度,也得到了稍高的测试集精度,这也证实了我们的直觉,即更复杂的模型应该性能更好。

我们还可以研究使用正则化更强的模型时会发生什么。设置C=0.01:

logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train)
print("Training set socre: {:.3f}".format(logreg001.score(X_train, y_train)))
print("Test set socre: {:.3f}".format(logreg001.score(X_test, y_test)))
Training set socre: 0.934
Test set socre: 0.930

我们可以发现将默认已经欠拟合的模型更加欠拟合,训练接和测试集精度比采用默认参数时更小。

看一下正则化参数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('Coefficient index')
plt.ylabel('coefficient magnitude')
plt.legend()

线性模型

LogisticRegression默认使用L2正则化。更强的正则化使得系数更趋向于0,但系数永远不会正好等于0.进一步观察图像,还可以在第三个系数那里发现有趣之处,这个系数是“平均周长”(mean perimeter)。C=100和C=1时,这个系数为负,而C=0.01时这个系数为正,系数可以告诉我们某个特征与哪个类别有关。例如,人们可能会认为高“纹理错误”(texture error)特征与“恶性”样本有关。但“平均周长”系数的正负号发生变化,说明较大的“平均周长”可以被当作“良性”或“恶性”的指标,具体取决于我们考虑的是哪个模型。这样说明,对线性模型的解释应该持保留态度。

如果想要一个可解释性强的模型,使用L1正则化可能更好,因为它约束模型只使用少数几个特征。下面是使用L1正则化的系数图像和分类精度:

for C, marker in zip([0.01, 1, 100], ['o', '^', 'v']):
    logreg_l1 = LogisticRegression(C=C, penalty="l1").fit(X_train, y_train)
    print("Training accuracy of l1 logreg with C={:.3f}: {:.2f}".format(C, logreg_l1.score(X_train, y_train)))
    print("Test accuracy of l1 logreg with C={:.3f}: {:.2f}".format(C, logreg_l1.score(X_test, y_test)))

    plt.plot(logreg_l1.coef_.T, marker, label="C={:.3f}".format(C))
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
plt.hlines(0, 0, cancer.data.shape[1])
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.ylim(-5, 5)
plt.legend(loc=3)
Training accuracy of l1 logreg with C=0.010: 0.92
Test accuracy of l1 logreg with C=0.010: 0.93
Training accuracy of l1 logreg with C=1.000: 0.96
Test accuracy of l1 logreg with C=1.000: 0.96
Training accuracy of l1 logreg with C=100.000: 0.99
Test accuracy of l1 logreg with C=100.000: 0.98

线性模型

如上图所示,用于分类的线性模型与用于回归的线性模型有许多相似之处。与用于回归的线性模型一样,模型的主要差别在于penalty参数,这个参数会影响正则化,也会影响模型时使用所有特征还是只选择特征的一个子集。

6.用于多分类的线性模型

许多线性分类模型只适用于二分类问题,不能轻易的推广到多分类问题(除了Logistic回归)。将二分类方法推广到多分类的一种常见方法是“一对其余”(one-vs-rest)方法。在“一对其余”方法中,对每个类别都学习一个二分类模型,将这个类别与其他类别尽量分开,这样就生成了与类别个数一样多的二分类模型。在测试点上运行所有二分类分类器来进行预测。在在对应类别上分数最高的分类器“胜出”,将这个类别返回作为预测结果。

每个类别都对应一个二类分类器,这样每个类别也都有一个系数(w)向量和一个截距(b)。下面是分类置信方程,其结果中最大值对应的类别即为预测的类比标签:

w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b

多分类Logistic回归背后的数学与“一对其余”方法稍有不同,但它也是对每个类别都有一个系数向量和一个截距,也使用了相同的预测方法。

我们将“一对其余”方法应用在一个简单的三分类数据集上。我们用到了一个二维数据集,每个类别的数据都是从一个高斯分布中采样得出的:

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", "class2"])

线性模型

在这个数据集上训练一个LinearSVC分类器:

linear_svm = LinearSVC().fit(X, y)
print("Training set score: {:.2f}".format(linear_svm.score(X, y)))
print("Coefficient shape:", linear_svm.coef_.shape)
print("Intercept shape:", linear_svm.intercept_.shape)
Training set score: 1.00
Coefficient shape: (3, 2)
Intercept shape: (3,)

将这三个二分类器给出的直线可视化:

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', 'Line Class 0', 'Line Class 1', 'Line Class 2'], loc=[1.01, 0.3])

线性模型

可以看到,训练集中所有属于类别0的点都在于类别0对应的直线上方,这说明它们位于这个二类分类器属于“类别0”的那一侧。属于类别0的点位于与类别2对应直线的上方,这说明类别0的点被类别2的二类分类器划为“其余”。属于类别0的点位于与类别1对应的直线左侧,这说明类别1的二类分类器将类别0也划为“其余”。

图像中间的三角形区域和同时属于两个分类的区域属于哪一个类别呢,3个二类分类器都将中间区域的点划为“其余”,将公有的区域两个二类分类器划为“本类”,剩下一个二类分类器划为“其余”。这些区域的点应该划到哪一个类别呢?答案是分类方程结果最大的那个类别,即最接近的那条线对应的类别。

下面的例子给出了二维空间中所有区域的预测结果:

mglearn.plots.plot_2d_classification(linear_svm, X, fill=True, 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', 'Line Class 0', 'Line Class 1', 'Line Class 2'], loc=[1.01, 0.3])

线性模型

7. 线性模型的优点、缺点和参数

线性模型的主要参数是正则化参数,在回归模型中叫作alpha,在LogisticRegression和LiearSVC中叫作C。alpha值越大或C值越小,对应的正则化越强,说明模型越简单。通常在对数尺度上对C和alpha进行搜索。还需要确定是使用L1正则化还是使用L2正则化。如果假定只有几个特征时真正重要的,那么应该使用L1正则化。否则应默认使用L2正则化。如果模型的可解释性很重要的话,使用L1正则化也会有帮助。由于L1只用到几个特征,所以相对更容易解释那些特征对模型是重要的,以及这些特征的作用。

线性模型的训练速度非常快,预测速度也很快。这种模型可以推广到非常大的数据集,对稀疏数据也很有效。如果你的数据包含数十万甚至上百万个样本,你可能需要研究如何使用LogisticRegression和Ridge模型的slover=’sag’选项,在处理大型数据时,这一选项比默认值要更快。其他选项还有SGDClassifier类和SGDRegression类,它们对本节介绍的线性模型实现了可拓展性更强的版本。

线性模型的另一个优点在于,利用我们之前见过的用于回归和分类的公式,理解如何进行预测是相对比较容易的。但是往往并不完全清楚系数为什么是这样的。如果数据中包含高度相关的特征,这一问题尤为突出。在这种情况下,可能很难对系数做出解释。

如果特征数量大于样本数量,线性模型的表现通常很好。它也常用于非常大的数据集,只是因为训练其他模型并不可行。但在更低维的空间中,模型的泛化性能可能更好。

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...