Python机器学习基础教程学习笔记(6)——线性模型(分类)
1. 二分类
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
# 不想看到warnings
import warnings
warnings.filterwarnings("ignore", category=Warning)
# 拆分训练集与测试集
from sklearn.model_selection import train_test_split
# 使用两个分类算法:LogisticRegression和LinearSVC
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(clf.__class__.__name__)
ax.set_xlabel("Feature 0")
ax.set_ylabel("Feature 1")
ax.legend()
output_3_0.png
- LinearSVC和LogisticRegression两个模型默认都使用L2正则化
- 决定正则化强度的权衡参数叫做C。
- C值越大,对应的正则化越弱。
- C值较大,模型将尽可能将训练集拟合到最好
- C值较小,模型更强调使用系统向量接近于0
mglearn.plots.plot_linear_svc_regularization()
output_5_0.png
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 score: {:.3f}".format(logreg.score(X_train, y_train)))
print("Test set score: {:.3f}".format(logreg.score(X_test, y_test)))
Training set score: 0.953
Test set score: 0.958
- C=1的默认值给出了相当好的性能,都是95%的精度。
- 训练集和测试集的性能非常接近,所以很可能是欠拟合。
- 尝试增大C来拟合一个更灵活的模型
logreg100 = LogisticRegression(C=100).fit(X_train, y_train)
print("Training set score: {:.3f}".format(logreg100.score(X_train, y_train)))
print("Test set score: {:.3f}".format(logreg100.score(X_test, y_test)))
Training set score: 0.972
Test set score: 0.965
- 当减小C值时,正则化更强,训练集和测试集精度都变小
logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train)
print("Training set score: {:.3f}".format(logreg001.score(X_train, y_train)))
print("Test set score: {:.3f}".format(logreg001.score(X_test, y_test)))
Training set score: 0.934
Test set score: 0.930
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("coeffient magnitude")
plt.legend()
plt.show()
output_11_0.png
- LogisticRegression使用的是L2正则化
- 更强的正则化使用得系统趋向于0,但是系统永远不会正好等于0
- 对线性模型系统的解释应该始终持保留态度
- 如果想要解释性更强的模型,使用L1正则化可能更好,因为它约束模型只使用少数的几个特征
for C,marker in zip([0.001,1,100],['o','^','v']):
# 这里把penalty参数设置为l1,表示使用L1正则化
lr_l1= LogisticRegression(C=C,penalty="l1").fit(X_train,y_train)
print("C={:.3f}".format(C))
print("Training set score : {:.3f}".format(lr_l1.score(X_train, y_train)))
print("Test set score : {:.3f}".format(lr_l1.score(X_test, y_test)))
print("---------------------------------------")
plt.plot(lr_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.ylim(-5,5)
plt.xlabel("coefficient index")
plt.ylabel("coeffient magnitude")
plt.legend()
plt.show()
C=0.001
Training set score : 0.913
Test set score : 0.923
---------------------------------------
C=1.000
Training set score : 0.960
Test set score : 0.958
---------------------------------------
C=100.000
Training set score : 0.986
Test set score : 0.979
---------------------------------------
output_13_1.png
- 模型的主要差别在于penalty参数,这个参数会影响正则化,也会影响模型是使用所有可用特征还是只选择特征的一个子集
2. 多分类
将二分类算法推广到多分类算法的一种常见方法是“一对其余”(one-vs.-rest)
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()
output_17_0.png
linear_svm = LinearSVC().fit(X,y)
# coef_的形状是(3,2),说明coef_每行包含三个类别之一的系统微量每列包含某个特征(这个数据集有2个特征)对应的系数值。
print("Coefficient shape:{}".format(linear_svm.coef_.shape))
# intercept_的形状是(3,),是一维数组,保存每个类别的截距
print("Intercept shape:{}".format(linear_svm.intercept_.shape))
Coefficient shape:(3, 2)
Intercept shape:(3,)
mglearn.discrete_scatter(X[:,0],X[:,1],y)
line = np.linspace(-15,15)
# -(line*coef[0]+ intercept)/coef[1] 这个值可以简单理解一下
for coef,intercept,color in zip(linear_svm.coef_,linear_svm.intercept_,['b','r','g']):
plt.plot(line,-(line*coef[0]+ intercept)/coef[1],color)
plt.xlim(-10,8)
plt.ylim(-10,15)
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))
plt.show()
output_19_0.png
- 从图中可以看出这种“一对其余”(one-vs.-rest)的样子
- 但是图中间的三角形区域属于哪一个类别呢,3个二类分类器都将这一区域内的点划分为“其余”
- 答案是,分类方程结果最大的那个类别,即最接近的那条线对应的类别。
mglearn.plots.plot_2d_classification(linear_svm,X,fill=True,alpha=.3)
mglearn.discrete_scatter(X[:,0],X[:,1],y)
line = np.linspace(-15,15)
# -(line*coef[0]+ intercept)/coef[1] 这个值可以简单理解一下
for coef,intercept,color in zip(linear_svm.coef_,linear_svm.intercept_,['b','r','g']):
plt.plot(line,-(line*coef[0]+ intercept)/coef[1],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))
plt.show()
output_21_0.png
3 优点、缺点和参数
- 线性模型的主要参数是正则化参数
- 回归模型中叫alpha
- 分类模型中叫C
- alpha值较大或C值较小,说明模型比较简单
- 还需要确定使用L1正则化还是L2正则化
- 如果假定只有几个特征是真正重要的,那么使用L1正则化,否则默认使用L2正则化
- 如果模型的可解释性很重要,使用L1会有帮助
- 线性模型的训练速度非常快,预测速度也很快。
- 可推广到非常大的数据集
- 稀疏数据也很有效
- 如果数据包含数十万甚至上百万个样本,需要研究如何使用LogisticRegression和Ridge模型的solver='sag'选项,在处理大数据时,这一选项比默认值更快
- 其他选项还有SGDClassifier类和SDGRegressor类,对本节介绍的线性模型实现了可扩展性更强的版本。
- 如果特征数量大于样本数量,线性模型表现通常都很好。
- 常用于非常大的数据集,只是因为训练其他模型并不可行。
- 在更低维的空间中,其他模型的泛化性能可能更好