上文学习从理论的角度(算法)学习了线性模型的一些知识
本文将使用python的模块来简单使用了解一些这些算法
线性模型
对于回归问题,线性模型预测的一般公式如下:
这里
到
表示单个数据点的特征(本例中特征个数为
),$w
b
ŷ
ŷ = w[0] * x[0] + b$
mglearn.plots.plot_linear_regression_wave()
plt.show()
线性回归(又名普通最小二乘法)
线性回归,或者普通最小二乘法(ordinary least squares,OLS),是回归问题最简单也最经 典的线性方法。线性回归寻找参数
和
,使得对训练集的预测值与真实的回归目标值
之间的均方误差最小。均方误差(mean
squared error)是预测值与真实值之差的平方和除 以样本数。线性回归没有参数,这是一个优点,但也因此无法控制模型的复杂度。
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
X0, y0 = mglearn.datasets.make_wave(n_samples=60)
X_train0, X_test0, y_train0, y_test0 = train_test_split(X0, y0, random_state=42)
lr = LinearRegression().fit(X_train0, y_train0)
print("lr.coef_: {}".format(lr.coef_))
print("lr.intercept_: {}".format(lr.intercept_))
"""
“斜率”参数(w,也叫作权重或系数)被保存在 coef_ 属性中,而偏移或截距
(b)被保 存在 intercept_ 属性中,这里的下划线“_”是用于与用户设置的参
数区分开来
lr.coef_: [0.39390555]
lr.intercept_: -0.031804343026759746
"""
print("Training set score: {:.2f}".format(lr.score(X_train0, y_train0)))
print("Test set score: {:.2f}".format(lr.score(X_test0, y_test0)))
"""
Training set score: 0.67
Test set score: 0.66
"""
################################
# 更高维的数据集进行训练 #
################################
#这里使用的Boston的房价数据集(506,104) 一共506个样本,104个特征
X, y = mglearn.datasets.load_extended_boston()
X_train, X_test, y_train, y_test = train_test_split(X, y,random_state=0)
lr1 = LinearRegression().fit(X_train, y_train)
print("Traning set score: {:.2f}".format(lr1.score(X_train,y_train)))
print(X_test.shape)
print("Test set score: {:.2f}".format(lr1.score(X_test ,y_test)))
"""
Traning set score: 0.95
Test set score: 0.61
"""
岭回归
岭回归也是一种用于回归的线性模型,因此它的预测公式与普通最小二乘附加法相同。但在岭回归中,对系数(
)的选择不仅要在训练数据上得到好的预测结果,而且还要拟合约束。我们还希望系数尽量小。换句话说,
的所有元素都应接近于0。直观上来看,这意味着每个特征对输出的影响应尽可能小(即斜率很小),同时仍给出很好的预测结果。
这种约束是所谓正则化(
)的一个例子。正则化是指对模型做显式约束以避免过拟合。岭回归用到的这种被称为L2正则化。
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在训练集的分数高于测试集的分数,与预期一致。线性回归存在过拟合,而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.93
Test set score: 0.77
"""
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)))
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()
plt.show()
mglearn.plots.plot_ridge_n_samples()
plt.show()
Lasso 回归
from sklearn.linear_model import Lasso
#同样使用Boston的房价数据集
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("Number of features used: {}".format(np.sum(lasso.coef_ != 0)))
"""
Training set score: 0.29
Test set score: 0.21
Number of features used: 4
如你所见,Lasso 在训练集与测试集上的表现都很差。这表示存
在欠拟合,我们发现模型 只用到了 105 个特征中的 4 个。与
Ridge 类似,Lasso 也有一个正则化参数 alpha,可以控 制系
数趋向于 0 的强度。在上一个例子中,我们用的是默认值alpha=1.0。
为了降低欠拟合,我们尝试减小 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("Number of features used: {}".format(np.sum(lasso001.coef_ != 0)))
"""
Training set score: 0.90
Test set score: 0.77
Number of features used: 33
可以看出alpha值变小,可以拟合一个更复杂的模型,在训练集和测试集
上的表现也更好。模型性能比使用 Ridge 时略好一点,而且我们只用到
105 个特征中的 33 个。
但如果把alpha 设得太小,那么就会消除正则化的效果,并出现过拟合,
得到与 LinearRegression 类似的结果
"""
lasso0001=Lasso(alpha=0.0001,max_iter=100000).fit(X_train,y_train)
print("Training set score :{:.2f}".format(lasso0001.score(X_train,y_train)))
print("Test set score: {:.2f}".format(lasso0001.score(X_test ,y_test)))
print("Number of features used:{}".format(np.sum(lasso0001.coef_!=0)))
"""
此时的正则化很弱,太多的线性相关的参数不为零
Training set score :0.95
Test set score: 0.64
Number of features used:96
"""
plt.plot(lasso.coef_, 's', label="Lasso alpha=1")
plt.plot(lasso001.coef_, '^', label="Lasso alpha=0.01")
plt.plot(lasso0001.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")
plt.show()
用于分类的线性模型
我们首先来看二分类。这时可以利用下面的公式进行预测:
最常见的两种线性分类算法是
回归(
)和线性支持向量机(
,线性
),前者在linear_model.LogisticRegression
中实现, 后者在svm.LinearSVC
(
代表支持向量分类器)中实现。虽然LogisticRegression
的名字中含有回归(
),但它是一种分类算法,并不是回归算法,不应与 LinearRegression
混淆。
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()
plt.show()
上图第一特征位于x轴,第二个特征位于y轴,分别展示了LinearSVC
和LogisticRegression
得到的决策边界,都是直线。但上图都有分类错误的点,两个模型都默认使用
正则化对于LogisticRegression
和 LinearSVC
,决定正则化强度的权衡参数叫作
。
值越大,对应的正则化越弱。换句话说,如果参数
值较大,那么LogisticRegression
和LinearSVC
将尽可能将训练集拟合到最好,而如果
值较小,那么模型更强调使系数向量(
)接近于
。参数
的作用还有另一个有趣之处。较小的
值可以让算法尽量适应“大多数”数据点, 而较大的
值更强调每个数据点都分类正确的重要性
mglearn.plots.plot_linear_svc_regularization()
plt.show()
LogisticRegression详细分析
from sklearn.datasets import load_breast_cancer
cancer=load_breast_cancer()
X_train2,X_test2,y_train2,y_test2=train_test_split(cancer.data,cancer.target,stratify=cancer.target,random_state=42)
logreg=LogisticRegression().fit(X_train2,y_train2 )
print("Training score: {:.4f}".format(logreg.score(X_train2,y_train2) ))
print("Test score: {:.4f}".format(logreg.score(X_test2,y_test2)))
"""
Training score: 0.9484
Test score: 0.9580
C=1 的默认值给出了相当好的性能,在训练集和
测试集上都达到 95% 的精度。但由于训练集和
测试集的性能非常接近,所以模型很可能是欠拟
合的。我们尝试增大C来拟合一个更灵活的模型
"""
logreg001 = LogisticRegression(C=0.01).fit(X_train2, y_train2)
print("Training1 set score: {:.3f}".format(logreg001.score(X_train2, y_train2)))
print("Test set1 score: {:.3f}".format(logreg001.score(X_test2, y_test2)))
"""
Training1 set score: 0.937
Test set1 score: 0.930
C=0.01时,此时已经欠拟合的模型继续向左移动,精度都下降
"""
logreg100 = LogisticRegression(C=100).fit(X_train2, y_train2)
print("Training2 set score: {:.3f}".format(logreg100.score(X_train2, y_train2)))
print("Test set2 score: {:.3f}".format(logreg100.score(X_test2, y_test2)))
"""
Training2 set score: 0.944
Test set2 score: 0.958
c=100时,可以得到更高的训练集、测试集精度
说明更复杂的模型性能更好
"""
# 下面查看不同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.001")
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()
plt.show()
引用
《Python机器学习基础教程》 人 民 邮 电 出 版 社
维基百科