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随机拆分时会出现训练集与测试集存的样本比例出现较大差异)。

相关推荐
请你喝好果汁6412 小时前
TWASandGWAS中GBS filtering and GWAS(1)
信息可视化·数据挖掘·数据分析
Leo.yuan2 小时前
数据分析怎么做?高效的数据分析方法有哪些?
大数据·数据库·信息可视化·数据挖掘·数据分析
人大博士的交易之路9 小时前
今日行情明日机会——20250512
大数据·数学建模·数据挖掘·缠论·缠中说禅·涨停回马枪
yzx9910131 天前
支持向量机与逻辑回归的区别及 SVM 在图像分类中的应用
支持向量机·分类·逻辑回归
鸿蒙布道师1 天前
英伟达开源Llama-Nemotron系列模型:14万H100小时训练细节全解析
深度学习·神经网络·opencv·机器学习·自然语言处理·数据挖掘·llama
慕婉03071 天前
如何理解编程中的递归、迭代与回归?
人工智能·数据挖掘·回归
大刘讲IT1 天前
轻量化工业互联网平台在中小制造企业的垂直应用实践:架构、集成、数据价值与选型策略
大数据·学习·程序人生·架构·数据挖掘·能源·制造
泡芙萝莉酱1 天前
各省份发电量数据(2005-2022年)-社科数据
大数据·人工智能·深度学习·数据挖掘·数据分析·毕业论文·数据统计
shadowtalon2 天前
基于CNN的猫狗图像分类系统
人工智能·深度学习·神经网络·机器学习·计算机视觉·分类·cnn