线性模型
线性模型是实践中使用比较广泛的模型,利用输入数据的线性函数进行预测。
用于回归的线性模型
回归问题使用的显现函数如下:
y
^
=
W
∗
X
+
b
=
w
[
0
]
∗
x
[
0
]
+
w
[
1
]
∗
x
[
1
]
+
⋅
⋅
⋅
+
w
[
p
]
∗
x
[
p
]
+
b
\hat{y} =W*X+b= w[0]*x[0]+w[1]*x[1]+···+w[p]*x[p]+b
y^=W∗X+b=w[0]∗x[0]+w[1]∗x[1]+⋅⋅⋅+w[p]∗x[p]+b
X={x[0],x[1],x[2],···,x[p]}是输入数据点的特征,W和b是模型参数,
y
^
\hat{y}
y^是模型预测结果。如果输入数据特征单一,则X = x[0].
如果给定数据只有一个特征,则
y
^
=
w
[
0
]
∗
x
[
0
]
+
b
\hat{y} = w[0]*x[0]+b
y^=w[0]∗x[0]+b
这边类似于一元一次线性方程,w[0]是方程的斜率,b是方程的截距。
我们可以用sklearn的wave数据集进行观测:
import mglearn.datasets
import matplotlib.pyplot as plt
mglearn.plots.plot_linear_regression_wave()
plt.show()
预览(图1)
与之前的KNN模型的可视化图对比,会发现线性模型预测能力十分受限,数据细节都丢失了。是因为观察数据点只有一个维度的特征,如果数据点有多个维度的特征,那线性模型可以表现出十分好的性能。
线性回归(最小二乘法)
线性回归是最简单也最经典的线性方法,是寻找参数w和b使得训练集的预测值和真实回归目标值y之间的均方误差最小。
MSE: Mean Squared Error
均方误差是指参数估计值与参数真值之差平方的期望值;
MSE可以评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具有更好的精确度。
M
S
E
=
1
N
∑
t
∈
1
N
(
y
−
y
^
)
2
MSE=\frac{1}{N}\sum_{t \in{1}}^{N} (y - \hat{y})^2
MSE=N1t∈1∑N(y−y^)2
图一可以使用下面代码生成:
from sklearn.linear_model import LinearRegression
from mglearn.datasets import make_wave
X,y = make_wave(n_samples=60)
Xtrain,Xtest ,ytrain,ytest = train_test_split(X,y,random_state=0)
lr = LinearRegression().fit(Xtrain,ytrain)
print( "lr.coef_ is {}".format(lr.coef_))
print( "lr.intercept_ is {}".format(lr.intercept_))
输出
lr.coef_ is [0.44153666]
lr.intercept_ is -0.01711124414733381coef_和intercept_都包含了下划线,原因是sklearn为了将其与用户定义的参数区分开。 系数(斜率) 的参数w被保存在coef_中,intercept_保存了偏移(截距) b 的值
上述代码是对wave数据集(数据点只有一个特征),结果可能太过于片面。如果使用波士顿房价数据集(包含506个样本,105个测试特征)。使用之前线性模型
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import mglearn.datasets
x,y = mglearn.datasets.load_extended_boston()
xtrain,xtest ,ytrain,ytest = train_test_split(x,y,random_state=0)
fits = LinearRegression().fit(xtrain, ytrain)
print("Train set score is {:.2}".format(fits.score(xtrain,ytrain)))
print("Test set score is {:.2}".format(fits.score(xtest,ytest)))
输出
Train set score is 0.95
Test set score is 0.61
我们可以看到测试集的结果远低于训练集,即模型过拟合了,我们可以通过正则化降低过拟合。
岭回归(ridge regression)
岭回归也是一种线性回归的模型,和之前的最小二乘法相同。但是为了减小过拟合,我摸会附加约束条件,是的参数w尽可能的小,同时还能给出预测结果。
正则化有两种L1正则化:
L
1
:
J
=
J
0
+
α
∑
w
∣
w
∣
L1: J = J_0 + \alpha\sum_{w}|w|
L1:J=J0+αw∑∣w∣
和L2正则化:
L
2
:
J
=
J
0
+
α
∑
w
w
2
L2: J = J_0 + \alpha\sum_{w}w^2
L2:J=J0+αw∑w2
都是对原始损失函数
J
0
J_0
J0添加约束值。L1正则化和L2正则化的详细直观解释
岭回归使用的是L2正则化,代码:
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import mglearn.datasets
x, y = mglearn.datasets.load_extended_boston()
xtrain, xtest, ytrain, ytest = train_test_split(x, y, random_state=0)
reg = Ridge().fit(xtrain, ytrain)
score1 = reg.score(xtrain,ytrain)
score2 = reg.score(xtest,ytest)
print("Train set score is {:.2}".format(score1))
print("Test set score is {:.2}".format(score2))
输出
Train set score is 0.89
Test set score is 0.75
可以看到虽然训练集的结果低于线性回归,但是模型泛化能力变好了。对于该模型的参数中存在一个 α \alpha α,默认是1 ,该参数增大会使得系数更趋向于0,降低训练集性能,提高模型泛化能力。我们分别对 α \alpha α设置不同值,查看其泛化能力:
reg = Ridge(alpha=0.1).fit(xtrain, ytrain)
score1 = reg.score(xtrain,ytrain)
score2 = reg.score(xtest,ytest)
print("Train set score is {:.2}".format(score1))
print("Test set score is {:.2}".format(score2))
Train set score is 0.93
Test set score is 0.77
如果alpha的值过小,对系数限制就小,可能产生结果和最小二乘一样过拟合,如果吧alpha设置为10则:
reg = Ridge(alpha=10).fit(xtrain, ytrain)
score1 = reg.score(xtrain,ytrain)
score2 = reg.score(xtest,ytest)
print("Train set score is {:.2}".format(score1))
print("Test set score is {:.2}".format(score2))
Train set score is 0.79
Test set score is 0.64
我们对于不同的alpha值的岭回归模型的coef_值进行可视化:
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
import mglearn.datasets
import matplotlib.pyplot as plt
from sklearn.linear_model import Lasso
x, y = mglearn.datasets.load_extended_boston()
xtrain, xtest, ytrain, ytest = train_test_split(x, y, random_state=0)
reg10 = Ridge(alpha=10).fit(xtrain, ytrain)
reg1 = Ridge(alpha=0.1).fit(xtrain, ytrain)
reg = Ridge().fit(xtrain, ytrain)
fit = LinearRegression().fit(xtrain, ytrain)
plt.plot(reg10.coef_, "s", label="Ridge alpha 10")
plt.plot(reg.coef_, "o", label="Ridge alpha 0.1")
plt.plot(reg1.coef_, "v", label="Ridge alpha 1")
plt.plot(fit.coef_, "^", label="regressLiner")
plt.ylim(-25, 25)
plt.xlabel("coffient")
plt.ylabel("cofficient magnitude")
plt.hlines(0, 0, len(fit.coef_))
plt.legend()
plt.show()
预览
这里x轴表示coef_的元素,数值代表对应索引值的特征系数。y轴代表系数实际值。
除了正则化参数,还有一种方法理解正则化的影响,就是改变数据量。
import mglearn.datasets
import matplotlib.pyplot as plt
mglearn.plots.plot_ridge_n_samples()
plt.show()
预览
可以看到,如果有足够数据集,正则化也不是那么重要。
lasso回归
除了岭回归,lasso也是一种使用正则化约束模型的线性回归。但是使用的是L1 正则化,L1正则化是使得某些系数刚好为0,就是某些数据点的某些特征被完全忽视。
Lasso模型在sklearn的linear_model模块下 ,我们同样使用它测试波士顿房价:
from sklearn.model_selection import train_test_split
import mglearn.datasets
from sklearn.linear_model import Lasso
import numpy as np
x, y = mglearn.datasets.load_extended_boston()
xtrain, xtest, ytrain, ytest = train_test_split(x, y, random_state=0)
lasso = Lasso().fit(xtrain,ytrain)
print("Training set score is :{:.2}".format(lasso.score(xtrain,ytrain)))
print("Test ser score is :{:.2}".format(lasso.score(xtest,ytest)))
print("Number of feature user:{}".format(np.sum(lasso.coef_ !=0) ))
输出
Training set score is :0.29
Test ser score is :0.21
Number of feature user:4
我们可以看到,模型结果很差。因为对于波士顿房价数据集中,每个数据点有105个特征,而在这里只用到了4个。L1正则化同样也拥有一个参数
α
\alpha
α
L1正则化:
L
1
:
J
=
J
0
+
α
∑
w
∣
w
∣
L1: J = J_0 + \alpha\sum_{w}|w|
L1:J=J0+αw∑∣w∣
对于这个参数,默认是alpha = 1 ,我们可以通过改变这个参数来改变模型的性能。L1中的参数变小,增加模型复杂度,但如果太小会导致正则化失效,模型过拟合。
from sklearn.model_selection import train_test_split
import mglearn.datasets
from sklearn.linear_model import Lasso
import numpy as np
x, y = mglearn.datasets.load_extended_boston()
xtrain, xtest, ytrain, ytest = train_test_split(x, y, random_state=0)
lasso = Lasso(alpha=0.01,max_iter=100000).fit(xtrain,ytrain)
print("Training set score is :{:.2}".format(lasso.score(xtrain,ytrain)))
print("Test ser score is :{:.2}".format(lasso.score(xtest,ytest)))
print("Number of feature user:{}".format(np.sum(lasso.coef_ !=0) ))
输出
Training set score is :0.9
Test ser score is :0.77
Number of feature user:33
我们将不同参数的Lasso回归模型与Ridge回归模型可视化:
from sklearn.model_selection import train_test_split
import mglearn.datasets
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso
import numpy as np
import matplotlib.pyplot as plt
x, y = mglearn.datasets.load_extended_boston()
xtrain, xtest, ytrain, ytest = train_test_split(x, y, random_state=0)
lasso = Lasso().fit(xtrain,ytrain)
lasso001 = Lasso(alpha=0.01,max_iter=100000).fit(xtrain,ytrain)
reg = Ridge().fit(xtrain, ytrain)
lasso00001 = Lasso(alpha=0.0001,max_iter=100000).fit(xtrain,ytrain)
plt.plot(lasso.coef_, "s", label="lasso alpha 1")
plt.plot(lasso001.coef_, "o", label="lasso alpha 0.01")
plt.plot(lasso00001.coef_, "v", label="lasso alpha 0.00001")
plt.plot(reg.coef_, "^", label="Ridge ")
plt.ylim(-25, 25)
plt.xlabel("coffient")
plt.ylabel("cofficient magnitude")
plt.legend()
plt.show()
预览
可以看到档Alpha = 1 时,lasso回归的大部分系数都是0,其他系数也很小,当alpha = 0.01时得到橙色圆形,大部分特征也是0。所以当增大alpha会增加正则化的约束。
在实践中,一般首选岭回归,但如果特征很多,也能确定其中只有几个是很重要的,那么选择Lasso回归更好。同时Lasso的可解释性更好,因为他只选择了一部分特征。
sklearn中linear_model模块拥有另一种模型:ElasticNet,结合了L1和L2正则化的惩罚项,但需要调节两个参数。
用于分类的线性模型
线性模型也用于分类任务,对于二分类如下
y
^
=
W
∗
X
+
b
=
w
[
0
]
∗
x
[
0
]
+
w
[
1
]
∗
x
[
1
]
+
⋅
⋅
⋅
+
w
[
p
]
∗
x
[
p
]
+
b
>
0
\hat{y} =W*X+b= w[0]*x[0]+w[1]*x[1]+···+w[p]*x[p]+b >0
y^=W∗X+b=w[0]∗x[0]+w[1]∗x[1]+⋅⋅⋅+w[p]∗x[p]+b>0
我们不在像回归一样,去求一个准确的值,而是寻找一个阈值,如果预测值
y
^
>
0
\hat{y}>0
y^>0 我们认为预测类别+1,反之-1。对于回归,我们是使用线性模型输出的是一个函数、平面或者超平面。而对于分类,我们是使用这个输出作为边界来划分类别。
线性模型有很多种算法,区别在于:
- 系数和截距的特定组合对训练数据拟合好坏的度量方法。
- 是否使用正则化,使用那个正则化。
最常见的线性分类算法有两种:Logistics 回归(Logistics regression)和线性支持向量机(线性SVM)详细内容看—>逻辑回归详解.
我们可以将Logistics regression和LinearSVC模型应用到forge上,并将其可视化:
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.model_selection import train_test_split
import mglearn.datasets
import matplotlib.pyplot as plt
x, y = mglearn.datasets.make_forge()
figs, axes = plt.subplots(1, 2, figsize=(10, 3))
for model, axe in zip([LogisticRegression, LinearSVC], axes):
fit = model().fit(x, y)
mglearn.plots.plot_2d_separator(fit, x, fill=False, eps=0.5, ax=axe, alpha=0.7)
mglearn.discrete_scatter(x[:, 0], x[:, 1], y, ax=axe)
axe.set_title("{}".format(fit.__class__.__name__))
axe.set_xlabel("Feature 0")
axe.set_ylabel("Feature 1")
axes[0].legend()
plt.show()
预览
这两个模型都使用了L2正则化,决定正则化强度的参数是C,C越大对应正则化越弱。C越大,意味着模型可能更容易过拟合,如果C越小,意味着模型的系数向量w更接近于0。
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
cancer = load_breast_cancer()
Xtrain, Xtest, ytrain, ytest = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=42)
logreg = LogisticRegression().fit(Xtrain, ytrain)
print("Training set score is {:.3}".format(logreg.score(Xtrain, ytrain)))
print("Test set score is {:.3}".format(logreg.score(Xtest, ytest)))
logreg100 = LogisticRegression(C=100).fit(Xtrain, ytrain)
print("Training set score is {:.3}".format(logreg100.score(Xtrain, ytrain)))
print("Test set score is {:.3}".format(logreg100.score(Xtest, ytest)))
logreg001 = LogisticRegression(C=0.01).fit(Xtrain, ytrain)
print("Training set score is {:.3}".format(logreg001.score(Xtrain, ytrain)))
print("Test set score is {:.3}".format(logreg001.score(Xtest, ytest)))
输出
Training set score is 0.958
Test set score is 0.958
Training set score is 0.984
Test set score is 0.972
Training set score is 0.953
Test set score is 0.951
如果有警告:
则在 LogisticRegression(max_iter=5000)添加最大迭代次数。
对上述不同参数值进行可视化话后:
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.001")
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
xlims = plt.xlim()
plt.hlines(0, xlims[0], xlims[1])
plt.xlim(xlims)
plt.ylim(-5, 5)
plt.xlabel("Feature")
plt.ylabel("Coefficient magnitude")
plt.legend()
plt.show()
预览
如果要使模型使用L1正则化,则需要使用模型参数penalty:
LogisticRegression(penalty="l1")
小结
- 线性模型主要参数就是正则化参数,回归模型中叫做alpha,分类模型为C
- alpha值越大或者C的值越小,模型就会越简单
- 如果确定数据点中特征数只有几个有用,那就使用L1正则化,否则使用L2
- 如果模型可解释性很重要,则使用L1正则化
- 线性模型训练速度非常快,在稀疏矩阵也可以得到很好的效果。
- 对于回归和分类任务的公式,理解如何预测是相对容易的