02_线性模型(回归分类模型)

用于分类的线性模型

线性模型也广泛应用于分类问题,可以利用下面的公式进行预测:

\\widehat y = w\[0\]\*x\[0\]+w\[1\]\*x\[1\]+...+w\[p\]\*x\[p\]+b \> 0

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

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

最常见的两种线性分类算法是 Logistic 回归(logistic regression)和线性支持向量机(linear support vector machine,线性 SVM)

二分类

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

python 复制代码
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import mglearn
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
import warnings
warnings.filterwarnings('ignore')

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 的区域分开了。换句话说,对于每个分类器而言,位于黑线上方的新数据点都会被划为类别 1,而在黑线下方的点都会被划为类别 0。

注意,两个模型中都有两个点的分类是错误的。两个模型都默认使用 L2 正则化,就像 Ridge 对回归所做的那样。

对 于 LogisticRegression 和 LinearSVC, 决 定 正 则 化 强 度 的 权 衡 参 数 叫 作 C。C 值 越大,对应的正则化越弱。换句话说,如果参数 C 值较大,那么 LogisticRegression 和LinearSVC 将尽可能将训练集拟合到最好,而如果 C 值较小,那么模型更强调使系数向量(w)接近于 0。

参数 C 的作用还有另一个有趣之处。较小的 C 值可以让算法尽量适应"大多数"数据点,而较大的 C 值更强调每个数据点都分类正确的重要性。

python 复制代码
mglearn.plots.plot_linear_svc_regularization() # 不同 C 值的线性 SVM 在 forge 数据集上的决策边界

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

在乳腺癌数据集上详细分析 LogisticRegression

python 复制代码
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

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(logreg.score(X_train, Y_train),logreg.score(X_test, Y_test))

通过上例,在C=1 的(默认值)情况下,具有相当好的性能。但由于训练集和测试集的性能非常接近,所以模型很可能是欠拟合的。尝试增大 C 来拟合一个更灵活的模型:

python 复制代码
logreg10 = LogisticRegression(C=10).fit(X_train, Y_train)
print(logreg10.score(X_train, Y_train),logreg10.score(X_test, Y_test))

logreg100 = LogisticRegression(C=100).fit(X_train, Y_train)
print(logreg100.score(X_train, Y_train),logreg100.score(X_test, Y_test))

logreg1000 = LogisticRegression(C=1000).fit(X_train, Y_train)
print(logreg1000.score(X_train, Y_train),logreg1000.score(X_test, Y_test))

logreg10000 = LogisticRegression(C=10000).fit(X_train, Y_train)
print(logreg10000.score(X_train, Y_train),logreg10000.score(X_test, Y_test))

通过执行上例,可以看到随着C的增大,性能其实已经趋于一个稳定值(理论上应该是性能会更好,另外train_test_split中random_state取值不同,也会影响到性能,大概率是因为模型太小)

多分类的线性模型

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

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

w\[0\]\*x\[0\]+w\[1\]\*x\[1\]+...+w\[p\]\*x\[p\]+b

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

python 复制代码
from sklearn.datasets import make_blobs

X,Y = make_blobs(random_state=42)

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 对应的直线上方,这说明它们被类别 2 的二类分类器划为"其余"。属于类别 0 的点位于与类别 1 对应的直线左侧,这说明类别 1 的二元分类器将它们划为"其余"。

图像中间有块三角形区域,3 个二类分类器都将这一区域内的点划为"其余"。落在这个范围的数据,分类方程结果最大的那个类别,即最接近的那条线对应的类别。

鸢尾花的例子

python 复制代码
import pandas as pd
import numpy as np
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVC

iris = pd.read_csv(r'..\..\seaborn-data\iris.csv') # 加载数据
iris_class_dic = {'setosa':0, 'versicolor':1, 'virginica':2}
iris_class = ['setosa', 'versicolor', 'virginica']
iris_tz_array=iris.select_dtypes(include='number')
iris_class_array=iris['species'].map(iris_class_dic)

X_train,X_test,Y_train,Y_test = train_test_split(iris_tz_array,iris_class_array,random_state=42)
linear_svm = LinearSVC().fit(X_train,Y_train)
print(linear_svm.score(X_train,Y_train),linear_svm.score(X_test,Y_test)) # 测试分数能拿到1,训练分数达到了0.97

x_new= [[5,2.8,1,0.3]] # 预测分类
iris_class[linear_svm.predict(x_new)[0]]

总结

线性模型的主要参数是正则化参数,在回归模型中叫作 alpha,在 LinearSVC 和 Logistic-Regression 中叫作 C。alpha 值较大或 C 值较小,说明模型比较简单。特别是对于回归模型而言,调节这些参数非常重要。

目前对random_state的理解:train_test_split中的random_state可以指定不同的值,从目前的几个例子看这个值会影响到训练得分。如果存在较大差异,需要我们关注样本数据了(差异较大,很可能是样本数据太少,train_test_split随机拆分时会出现训练集与测试集存的样本比例出现较大差异)。

相关推荐
亿牛云爬虫专家1 小时前
NLP驱动网页数据分类与抽取实战
python·分类·爬虫代理·电商·代理ip·网页数据·www.goofish.com
电鱼智能的电小鱼15 小时前
虚拟现实教育终端技术方案——基于EFISH-SCB-RK3588的全场景国产化替代
linux·网络·人工智能·分类·数据挖掘·vr
小王毕业啦18 小时前
2022年 国内税务年鉴PDF电子版Excel
大数据·人工智能·数据挖掘·数据分析·数据统计·年鉴·社科数据
坚持就完事了18 小时前
平滑技术(数据处理,持续更新...)
信息可视化·数据挖掘·数据分析
liuweidong080219 小时前
【Pandas】pandas DataFrame sample
python·数据挖掘·pandas
华科云商xiao徐20 小时前
网页抓取混淆与嵌套数据处理流程
爬虫·数据挖掘
XYu1230121 小时前
豆瓣图书评论数据分析与可视化
python·数据挖掘·数据分析
Steve lu1 天前
回归任务和分类任务损失函数详解
pytorch·深度学习·神经网络·机器学习·分类·回归
AIBigModel1 天前
经典ReLU回归!重大缺陷「死亡ReLU问题」已被解决
人工智能·数据挖掘·回归
lishaoan772 天前
实验设计与分析(第6版,Montgomery著,傅珏生译) 第10章拟合回归模型10.9节思考题10.12 R语言解题
回归·r语言·线性回归·残差分析·实验设计与数据分析·回归显著性