动手学机器学习逻辑回归算法
往期文章
推荐书籍
代码:https://github.com/ForceInjection/hands-on-ML/blob/main/nju_software/Logistic%20Regression.ipynb
1. 关键概念
1.1 逻辑回归定义
在机器学习领域,逻辑回归(Logistic Regression)是一种广为人知且应用广泛的算法。尽管它的名字中包含 “回归”,但它实际上主要用于分类任务,尤其是二分类问题。所谓二分类问题,就是我们要将数据划分为两个互斥的类别,例如判断一封邮件是否为垃圾邮件,或者预测一个患者是否有某种疾病。
逻辑回归的核心思想是利用一个线性模型对输入特征进行加权求和,并映射到概率空间,从而实现分类任务。其线性预测公式为:
在这里, 是权重向量,它决定了每个特征在预测中的重要性; 是输入的特征向量,包含了样本的各种信息; 是偏置项,用于调整模型的预测结果。这个线性组合的结果 可以看作是模型对样本的一个综合评分。
为了将这个综合评分转化为概率值,逻辑回归引入了 Sigmoid 函数:
该函数呈现 S 形曲线,将任意实数映射到 区间,使其可被解释为概率。以下是 Sigmoid 函数的曲线示意图:
Sigmoid 函数将实数域映射到 (0,1) 区间,实现概率输出
当 很大时, 接近 1; 当 很小时, 接近 0。
这样一来,我们就可以根据这个概率值来判断样本更可能属于哪一类。通常,我们会设定一个阈值(比如 0.5),当概率大于或等于这个阈值时,将样本归为正类;否则归为负类。
举个例子,假设我们要预测一个学生是否能被大学录取。输入特征可以是学生的高考成绩、课外活动参与度等。权重向量 将根据这些特征对录取概率的影响程度进行调整,偏置项 则用于优化整个模型的预测效果。通过线性组合和 Sigmoid 函数,我们得到一个概率值,从而判断该学生被录取的可能性。
1.2 模型假设
在使用逻辑回归模型之前,我们需要了解一些基本假设,这些假设有助于我们更好地应用和解释模型。
输入特征 :逻辑回归对输入特征的分布无严格要求,例如不需要服从正态分布。然而,在实际应用中,特征的尺度差异较大会影响模型训练效果。此外,需要注意避免多重共线性。所谓多重共线性,就是输入特征之间存在高度相关的情况。例如,在研究房屋价格时,如果有两个特征 “房屋面积” 和 “房间数量”,这两个特征往往存在较强的相关性。这种情况下,模型在估计权重时可能会出现问题,因为很难区分这两个特征对房屋价格的独立影响。
输出类型 :逻辑回归主要用于预测类别概率。这意味着它不仅能告诉我们样本属于某个类别的可能性大小,还可以帮助我们进行更灵活的决策。例如,在营销活动中,我们可以根据用户购买产品的概率来制定个性化的营销策略,而不是简单地将用户划分为 “会购买” 或 “不会购买”。
决策边界 :默认情况下,逻辑回归假设决策边界是线性的。也就是说,模型通过一个线性的方程(由权重和偏置决定)将数据划分为两个类别。然而,在现实世界中,数据的分布可能更加复杂,无法用简单的直线来划分。这时,我们可以通过增加多项式特征等方式来扩展模型的非线性能力,构建更复杂的决策边界。例如,在对一个具有圆形分布的数据集进行分类时,我们可以通过增加特征的平方项来使模型学习到圆形的决策边界。
2. 原理与数学推导
2.1 损失函数推导
在训练逻辑回归模型时,我们需要定义一个损失函数来衡量模型的预测结果与真实标签之间的差异。这里我们采用的是基于最大似然估计的交叉熵损失函数。
设训练数据集包含 个独立样本,每个样本的预测概率为 ,真实标签为 。似然函数可以表示为所有样本预测概率的乘积:
为了方便计算,我们对似然函数取对数,得到对数似然函数。然后,为了将其转化为损失函数,我们取负数并除以样本数量 :
该损失函数衡量模型预测概率与真实标签的偏差。训练目标是通过优化算法最小化损失,从而学习最优参数。
2.2 参数优化
为了最小化损失函数,我们通常采用梯度下降算法。梯度下降的基本思想是通过计算损失函数对模型参数的梯度,然后沿着梯度的反方向更新参数,逐步逼近最优解。
参数更新公式为:
其中, 是学习率,它决定了每次更新的步长大小。
梯度的计算如下:
这个公式告诉我们,梯度的大小取决于模型预测概率与真实标签之间的误差,以及输入特征的值。通过不断迭代更新,模型的参数将逐渐调整到最优状态。
2.3 多分类扩展
虽然逻辑回归主要用于二分类问题,但也可以通过一些方法将其扩展到多分类任务。常用的方法是使用 Softmax 函数。
Softmax 函数可以将多个类别的预测分数转化为概率分布。假设我们有 个类别,每个类别的预测分数为 ,则 Softmax 函数公式为:
这个函数将每个类别的预测分数映射到 (0,1) 区间,并且所有类别的概率之和为 1。通过最大化真实类别的概率,我们可以训练出适用于多分类任务的逻辑回归模型。
3. 经典案例实战
3.1 鸢尾花分类(二分类)
在机器学习领域,鸢尾花分类是一个经典的入门案例。这里我们使用逻辑回归来解决鸢尾花的二分类问题。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineimport numpy as npimport matplotlib.pyplot as pltfrom sklearn.datasets import load_irisfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import accuracy_score, confusion_matrix# 数据加载与预处理iris = load_iris()X = iris.data[:, :2] # 仅使用前两个特征y = (iris.target != 0).astype(int) # 二分类问题# 划分训练集 / 测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 模型训练model = LogisticRegression(penalty='l2', C=1.0, solver='lbfgs', max_iter=200)model.fit(X_train, y_train)# 模型评估y_pred = model.predict(X_test)print("Accuracy:", accuracy_score(y_test, y_pred))print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))# 可视化决策边界x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1xx, yy = np.meshgrid(np.linspace(x_min, x_max, 200),np.linspace(y_min, y_max, 200))Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)plt.figure(figsize=(8, 6))plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.coolwarm)plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', cmap=plt.cm.coolwarm)plt.xlabel("Feature 1")plt.ylabel("Feature 2")plt.title("Logistic Regression Decision Boundary")plt.show()
这段代码首先加载了鸢尾花数据集,并选择了前两个特征进行二分类任务。然后将数据集划分为训练集和测试集,使用逻辑回归模型进行训练,并通过准确率和混淆矩阵评估模型的性能。最后,通过可视化决策边界,我们可以直观地看到模型的分类效果。
3.2 信用卡欺诈检测(类别不平衡)
在现实应用中,我们常常会遇到类别不平衡的问题。例如,在信用卡欺诈检测中,正常交易的数量通常远远多于欺诈交易。这种情况下,直接使用常规的分类方法可能会导致模型对少数类别(欺诈交易)的预测能力不足。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linefrom imblearn.over_sampling import SMOTEfrom sklearn.metrics import classification_report# 处理类别不平衡smote = SMOTE(random_state=42)X_res, y_res = smote.fit_resample(X_train, y_train)# 训练带权重的模型model = LogisticRegression(class_weight='balanced', max_iter=1000)model.fit(X_res, y_res)# 评估指标print(classification_report(y_test, y_pred, target_names=['正常', '欺诈']))# ROC曲线绘制from sklearn.metrics import RocCurveDisplayRocCurveDisplay.from_estimator(model, X_test, y_test)plt.plot([0,1], [0,1], linestyle='--')plt.title('ROC Curve')plt.show()
为了解决类别不平衡问题,这里我们使用了 SMOTE(合成少数过采样技术)来生成更多的少数类别样本。同时,在模型训练时,我们设置了 class_weight='balanced',让模型自动调整对不同类别的权重,以提高对少数类别的预测能力。通过分类报告,我们可以更全面地评估模型在不同类别上的性能。此外,绘制 ROC 曲线可以帮助我们直观地了解模型的分类效果。
4. 优化与改进
4.1 正则化实践
在机器学习中,正则化是一种常用的防止模型过拟合的技术。逻辑回归中常用的正则化方法有 L1 正则化和 L2 正则化。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line# 对比 L1/L2 正则化params = {'C': [0.001, 0.01, 0.1, 1, 10],'penalty': ['l1', 'l2'],'solver': ['liblinear']}grid = GridSearchCV(LogisticRegression(), params, cv=5)grid.fit(X_train, y_train)print("Best params:", grid.best_params_)
这段代码通过网格搜索的方式,对比了 L1 和 L2 正则化在不同正则化强度(参数 C)下的表现。通过交叉验证,我们可以找到最优的正则化参数组合,从而提高模型的泛化能力。
4.2 非线性扩展
当数据的分布较为复杂,无法用简单的线性模型拟合时,我们可以通过一些方法来扩展模型的非线性能力。
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(linefrom sklearn.preprocessing import PolynomialFeatures# 生成多项式特征poly = PolynomialFeatures(degree=2)X_poly = poly.fit_transform(X)# 训练非线性模型model = LogisticRegression(C=0.1)model.fit(X_poly_train, y_train)# 可视化非线性决策边界Z = model.predict(poly.transform(np.c_[xx.ravel(), yy.ravel()]))
这里我们使用了多项式特征生成器,将原始特征转换为包含多项式项的特征。通过增加这些非线性特征,模型可以学习到更复杂的决策边界,从而提高对复杂数据分布的拟合能力。
附录
梯度推导过程
梯度推导是理解模型优化过程的重要部分。对于逻辑回归的损失函数,我们可以通过以下步骤推导出梯度:
损失函数为:
推导步骤:
计算 Sigmoid导数:链式法则求导
具体推导过程请查看相关书籍。