资讯动态

逻辑回归完整实现:从损失函数到参数估计算法详解

发布时间:2026/9/12 22:51:21 来源:尧图企业网站定制
简介面向机器学习课程期末大作业与实验环节的资料包围绕多项式拟合正弦函数、GMM高斯混合模型与逻辑回归三个经典主题打包了期末考试题、实验报告与可运行源码。逻辑回归部分覆盖两种损失函数的参数估计——无惩罚项与加入参数惩罚支持梯度下降、共轭梯度或牛顿法实现既可用高斯分布手工生成两类数据验证算法也可到UCI数据集上测试广告预测等真实场景。压缩包大小约4.45MB内容以Python源码、实验报告文档和试题文件为主并附有Windows64、PyCharm、Python3、Anaconda环境下的调试说明源码经严格调试可直接运行适合计科、人工智能、通信工程、自动化、电子信息等专业的学生用于课程设计、期末大作业或项目初期演示也便于在现有代码基础上修改扩展。当前已有170余人学习过该资源内含完整的实验目的、实验要求、算法设计思想与可复用代码能帮助读者快速掌握逻辑回归参数估计的完整流程并理解类条件分布不满足朴素贝叶斯假设时模型表现会受到何种影响。1. 从一次机器学习期末大作业说起逻辑回归为什么值得自己动手实现期末复习周最耗时间的不是背公式而是把一类算法的完整链路自己跑通。逻辑回归看似简单可实验要求里写明要实现无惩罚项和带惩罚项两种损失函数的参数估计并验证类条件分布不满足朴素贝叶斯假设时的表现这时候没有源码和实验报告参考很多细节要从头摸。这个压缩包把多项式拟合正弦函数、GMM 聚类和逻辑回归三块打包在一起前两者提供特征构造与数据生成的直觉逻辑回归承担主实验最后附期末考试题和完整实验报告。适合赶期末大作业的计算机、人工智能相关专业学生也适合想快速复习参数估计算法的从业者。Windows 64 位环境配 Anaconda 和 PyCharm跑 NumPy 与 scikit-learn 就能完整复现上手成本很低。2. 逻辑回归的两类损失函数无惩罚项与L2惩罚项的理论边界2.1 从线性判别到 sigmoid逻辑回归的模型假设先明确模型形式。给定特征向量 (x) 和参数 (w)逻辑回归先计算线性分数 (z w^Tx b)再通过 sigmoid 函数把 (z) 压缩到 (0,1) 区间作为 (P(y1|x)) 的估计。sigmoid 在 (z) 接近 0 时近似线性在两端趋于饱和这个非线性变换让线性模型也能输出概率而不是直接输出无界分数。实现时有个容易被忽略的细节当 (z) 很小或很大时np.exp(-z)会溢出产生nan或inf所以代码里要对输入做 clip 限制。import numpy as np def sigmoid(z): # 限制 z 的范围避免 exp 溢出 return 1.0 / (1.0 np.exp(-np.clip(z, -500, 500)))clip 的边界取 ±500 已经足够超过这个范围后 sigmoid 的输出要么趋近 0 要么趋近 1继续增大数值只会让 exp 计算不稳定对梯度更新没有实际帮助。教学实验里很多人第一次跑出nan就是因为少了这一步尤其是在没有特征归一化的情况下w 的某个分量可能快速增大。提示如果数据没有做标准化w 的不同分量尺度差异很大clip 边界可能还需要提高到 ±1000否则梯度更新前期仍可能溢出。逻辑回归属于判别模型它只建模条件概率 (P(y|x))不需要像朴素贝叶斯那样先估计类条件分布 (P(x|y))。这一点在实验要求的第 1 条里非常关键手工生成两组高斯分布数据时如果两组数据具有相同的协方差矩阵朴素贝叶斯的决策边界会趋于线性可一旦两个类别的协方差矩阵不同或者某个类本身是多模态的朴素贝叶斯对 (P(x|y)) 的独立假设就会引入偏差。逻辑回归直接拟合边界不关心 x 内部的结构因此在这种场景下通常更稳健。GMM 在这个实验中的角色就是生成那种“不满足朴素贝叶斯假设”的数据比如让同一个类别由两个相距较远的高斯簇组成。2.2 交叉熵损失与梯度的闭式推导把截距项 b 并进 w在 X 最左边补一列 1模型输出就是 σ(Xw)。损失函数采用交叉熵单样本损失为-[y_i log p_i (1-y_i) log(1-p_i)]全体样本取平均得到 J。这个形式来自伯努利分布的极大似然估计取负对数后就是交叉熵。为什么选择交叉熵而不是均方误差因为均方误差加上 sigmoid 以后目标函数关于 w 非凸梯度下降容易停在平坦区域而交叉熵的梯度形式上非常干净便于手工实现和验证。推导过程可以浓缩成三步先写出 σ(z) 的导数等于 σ(z)(1-σ(z))再对 log 项逐个求导最后利用分子分母互相抵消得到梯度表达式最终结果是grad (1/N) * X^T (σ(Xw) - y)这个形式意味着梯度的每一维都等于当前预测误差 (p - y) 在对应特征方向上的加权平均误差越大梯度越陡参数更新越快。落到代码里def compute_loss_and_grad(X, y, w): N X.shape[0] z np.dot(X, w) p sigmoid(z) # 加 1e-12 防止 log(0) 导致 nan loss -np.mean(y * np.log(p 1e-12) (1 - y) * np.log(1 - p 1e-12)) grad np.dot(X.T, p - y) / N return loss, grad函数返回两个值损失用于记录收敛过程梯度用于后续的梯度下降、共轭梯度或牛顿法。注意 p - y 的维度是 (N,)X.T 与它做矩阵乘法后得到 (D,) 的梯度与 w 的形状完全对应。如果你需要在实验报告里展示手写推导损失和梯度的闭式表达式可以不写矩阵形式改成累加形式更利于老师核对过程。2.3 加入L2惩罚项之后目标函数从单峰变成强凸实验要求的第 1 类损失是无惩罚项第 2 类是加入对参数的惩罚。最常见的惩罚是 L2 正则化目标函数变为J_reg(w) J(w) (λ / 2N) * Σ_{j1}^{D-1} w_j^2这里需要细看两件事。第一惩罚项通常只作用于特征权重不作用于截距项因为调整 w_0 只会平移决策边界不会改变边界复杂度sklearn 里的实现也是这么处理的。第二λ 除以 N 是为了让正则项与损失项的尺度保持一致因为你用的是平均交叉熵如果不除以样本量测试集大小变化时最优 λ 的取值会漂移。实现时把惩罚梯度和普通梯度分开计算不容易出错。def compute_loss_grad_l2(X, y, w, lmbda): N, D X.shape loss, grad compute_loss_and_grad(X, y, w) # 截距在 w[0]不惩罚 penalty lmbda / (2 * N) * np.sum(w[1:] ** 2) grad_pen np.zeros_like(w) grad_pen[1:] lmbda / N * w[1:] return loss penalty, grad grad_penlmbda就是正则化强度取 0 时退化为无惩罚项。加入 L2 后逻辑回归原本就凸的目标函数变成强凸意味着两点一是梯度下降的收敛速度从可能很慢变成确定收敛二是当特征维度高于样本数时Hessian 矩阵原本可能不可逆加惩罚后变成正定矩阵牛顿法可以直接求解。从模型角度理解L2 惩罚把每个权重向 0 收缩等价于对参数引入均值为 0 的高斯先验这在广告点击率预测这类高维稀疏特征场景中能有效抑制过拟合。目标函数凸性梯度下降收敛牛顿法可用性适用场景无惩罚项凸可能平坦慢且依赖学习率需样本量大于特征数低维、特征独立L2 惩罚项强凸稳定始终可逆高维、特征相关对期末实验来说低维合成数据上无惩罚项够用UCI 实际数据往往特征共线性强加 L2 后你能明显看到测试集准确率更平稳。实验报告中把这两行对比结论写清楚比贴大段推导更有说服力。2.4 从多项式拟合正弦函数到逻辑回归的特征扩展打包资源里单独有一个多项式拟合正弦函数的实验很多人在做逻辑回归时觉得这两个实验毫不相关但特征扩展的思想是相通的。正弦函数本身不是线性函数用 (y w_0 w_1x) 去拟合必然是欠拟合换成 (y w_0 w_1x w_2x^2 ... w_nx^n)阶数越高拟合能力越强。逻辑回归处理非线性分类边界时也做同样的事将原始特征转成多项式特征后原本线性不可分的点在新的多项式空间里可能就线性可分。from sklearn.preprocessing import PolynomialFeatures # degree3 会生成 [x1, x2, x1^2, x1*x2, x2^2, x1^3, ...] poly PolynomialFeatures(degree3, include_biasFalse) X_poly poly.fit_transform(X)degree是多项式阶数include_biasFalse表示不自动生成常数列因为逻辑回归里 w[0] 已经承担截距角色。做多项式拟合正弦函数实验时阶数从 3 开始逐步升到 15会看到训练误差一路下降而测试误差先降后升这就是过拟合的完整过程。回到逻辑回归上多项式特征同样带来过拟合风险配合 2.3 节的 L2 惩罚可以在高次项上施加收缩保留高次特征的同时限制它的影响。3. 手写参数估计算法梯度下降、共轭梯度与牛顿法的工程实现3.1 梯度下降学习率与收敛判据先用最直观的梯度下降把参数估计跑通。参数更新规则是w - w - lr * gradlr是学习率。实现上只需要关心三点初始化、停止条件、学习率调整。初始化直接取全零向量即可因为逻辑回归目标函数是凸的不同初始化会收敛到同一位置不会像神经网络那样陷入局部最优。def gd_fit(X, y, lr0.5, epochs500, lmbda0.0): N, D X.shape w np.zeros(D) for epoch in range(epochs): loss, grad compute_loss_grad_l2(X, y, w, lmbda) w - lr * grad if epoch % 50 0: print(fepoch {epoch}, loss {loss:.4f}) return w学习率是关键参数。lr 太大w 会在最优点附近来回震荡损失曲线像锯齿lr 太小500 轮可能还没走到低损失区域。我一般先用 0.5 跑一轮观察损失是否下降出现振荡就除以 10前 100 轮下降缓慢就乘 3。数据特征做标准化后学习率在 0.1 到 1 之间普遍有效。收敛判据除了固定轮数更常用的做法是看相邻两轮损失差值的绝对值小于某个阈值比如 1e-6同时限制最大轮数防止死循环。3.2 牛顿法用 Hessian 矩阵加速收敛梯度下降只用一阶信息每一步朝负梯度方向走收敛速度是线性的牛顿法则用 Hessian 矩阵刻画局部曲率参数更新变成w - w - H^{-1} grad收敛速度接近二阶。逻辑回归的 Hessian 矩阵可以直接写出闭式解H (1/N) X^T S X其中 S 是 N×N 对角矩阵对角线元素为p_i(1-p_i)。这个形式很优美因为 p_i 就是当前模型输出每一轮迭代时重新计算即可。def newton_fit(X, y, epochs20, lmbda0.0): N, D X.shape w np.zeros(D) for _ in range(epochs): p sigmoid(np.dot(X, w)) S np.diag((p * (1 - p)).flatten()) H np.dot(X.T, np.dot(S, X)) / N grad np.dot(X.T, p - y) / N # 加 L2 惩罚到 Hessian 和梯度 if lmbda 0: penalty_mat np.eye(D) * (lmbda / N) penalty_mat[0, 0] 0.0 H penalty_mat grad_pen np.zeros_like(w) grad_pen[1:] lmbda / N * w[1:] grad grad_pen w - np.linalg.solve(H, grad) return wnp.linalg.solve比手动计算 H 的逆矩阵更稳定它通过矩阵分解求解线性方程组避免了显式求逆带来的数值误差。注意当样本数 N 小于特征数 D 时X^T S X是奇异矩阵np.linalg.solve会抛出LinAlgError。这是正常现象说明需要加 L2 惩罚让 Hessian 变成正定矩阵而不是代码写错。牛顿法每轮代价远高于梯度下降因为要构造并分解 D×D 矩阵所以迭代轮数不需要多20 轮以内通常就收敛到很高精度。3.3 共轭梯度法只给梯度也能处理大规模参数共轭梯度法在逻辑回归里处于中间位置它不需要显式构造 Hessian 矩阵却保留了共轭方向带来的超线性收敛速度。手写完整 CG 逻辑稍长教学实验里更常见的做法是使用scipy.optimize.minimize的 CG 或 BFGS 方法只需要提供损失函数和梯度函数算法内部会管理搜索方向和步长。from scipy.optimize import minimize def cg_fit(X, y, lmbda0.0): N, D X.shape w0 np.zeros(D) def fun(w): loss, grad compute_loss_grad_l2(X, y, w, lmbda) return loss, grad res minimize(fun, w0, methodCG, jacTrue, options{maxiter: 200}) return res.xjacTrue告诉minimize传入的函数同时返回目标值和梯度这样才符合接口要求。maxiter设 200 是保险值逻辑回归的凸优化问题通常 50 次迭代以内就稳定。当数据量到几万、特征到几百时牛顿法需要反复分解矩阵内存和时间都吃紧共轭梯度法只需要梯度计算和向量乘法更适合这个量级。3.4 三种算法在合成数据上的横评在课程设计报告里把三种算法放到同一组人工数据上比较是一个稳妥的增分写法。数据用前面生成的二维高斯分类数据固定 500 个样本三种算法都收敛后比较三个指标达到相同训练损失所需的迭代轮数、每轮消耗的时间、最终在测试集上的准确率。运行时间依赖机器配置报告里建议写相对关系而不是具体秒数。算法每轮计算量需要二阶信息收敛速度适合的数据规模梯度下降O(ND)否慢线性特征少、先跑通流程共轭梯度O(ND) 少量向量运算否中特征中等到高牛顿法O(ND D^3)是快二阶样本和特征都不大写报告时注意一个常见误用很多人把牛顿法每轮迭代少当成“总时间少”在特征维度超过几千时牛顿法每轮求 Hessian 和矩阵分解的代价远高于梯度下降整体速度未必占优。横评的结论不应该是“牛顿法最优”而应该结合数据规模说明选型逻辑这样才显得你是自己调过参数而不是贴了一份编译通过就交付的代码。4. 用高斯分布人造数据验证当类条件不满足朴素贝叶斯假设时会怎样4.1 手工生成两类高斯数据与训练集划分实验要求第一项提到可以用高斯分布手工生成两类数据最省事的方式是用sklearn.datasets.make_classification。它会生成带有指定特征数、类别数和簇结构的合成数据每个簇内部呈高斯分布。参数里的n_clusters_per_class可以直接造出“一个类别包含多个高斯簇”的场景这正是考察朴素贝叶斯假设是否被破坏的实验变量。from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split # 2 个特征2 类每个类 1 个高斯簇 X, y make_classification( n_samples500, n_features2, n_redundant0, n_clusters_per_class1, flip_y0.05, random_state42 ) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state0 )n_redundant0表示不生成冗余特征保留原始两个有效维度方便最后在二维平面上画决策边界。flip_y设置 5% 的标签噪声更接近真实数据如果设为 0数据严格可分两类算法都能拿满分看不出差异。random_state固定后实验报告里的图和数字可以复现这一点在机器学习课程评分时很加分。Windows 64 位上的 Anaconda 已经自带这些库PyCharm 里新建一个环境直接逐段运行即可。4.2 朴素贝叶斯与逻辑回归的决策边界对比在同样的训练集上分别拟合 GaussianNB 和 LogisticRegression然后比较测试集准确率和决策边界形状。GaussianNB 假设每个类内的特征相互独立且服从高斯分布如果生成数据时两个类的协方差矩阵相同它的决策边界会接近一条直线但如果类间协方差不同边界会变成二次曲线而 GaussianNB 由于独立假设可能产生明显偏移。from sklearn.naive_bayes import GaussianNB from sklearn.linear_model import LogisticRegression gnb GaussianNB().fit(X_train, y_train) lr LogisticRegression(penaltyl2, C1.0, solverlbfgs).fit(X_train, y_train) print(GaussianNB acc:, gnb.score(X_test, y_test)) print(LogisticRegression acc:, lr.score(X_test, y_test))sklearn 里的 LogisticRegression 默认带 L2 惩罚C1.0是惩罚强度的倒数C 越小正则越强C 越大越接近无惩罚项。这里用默认参数主要是先拿到一个 baseline。准确率数字因数据而异但现象是一致的当两个类都只有一个高斯簇且协方差接近时两者测试准确率都在 0.95 左右当你把某类改成两个相距较远的簇时朴素贝叶斯准确率下降幅度明显超过逻辑回归因为特征在簇内和簇间呈现出的相关结构同时被独立假设抹掉了。4.3 用 GMM 叠加多模态分布彻底破坏独立性假设如果想让实验证据更硬就用 GMM 生成类内多模态数据。GaussianMixture 本身是生成模型先用n_components2拟合类别 0 的样本再用它采样出一批新样本类别 1 保持单高斯这样制造出的数据分布中类别 0 有两个相距较远的质心决策边界在特征平面上呈现出明显的非线性。from sklearn.mixture import GaussianMixture # 分别拟合两类数据的类条件分布 gmm0 GaussianMixture(n_components2, covariance_typefull, random_state0).fit(X[y 0]) gmm1 GaussianMixture(n_components1, random_state0).fit(X[y 1]) X0_new gmm0.sample(250)[0] X1_new gmm1.sample(250)[0]covariance_typefull允许每个高斯分量拥有完整的协方差矩阵意味着特征之间存在相关性这正是朴素贝叶斯的独立性假设无法覆盖的情况。GMM 在这里有两重角色一、作为数据生成器构造复杂类条件分布二、它本身就是期末题里常考的无监督聚类模型。资源里单独有一个 GMM 实验做完这个对比后试着把逻辑回归的输入换成原始特征加 GMM 输出的簇标签这种特征拼接思路在很多竞赛 baseline 里仍然有效。数据生成方式朴素贝叶斯现象逻辑回归现象同类单高斯协方差相同边界接近线性准确率高边界接近线性准确率高同类单高斯协方差不同独立假设导致边界偏移判别式边界更贴近真实GMM 多模态混合准确率明显下降仍能保持较好判别能力如果实验报告只放一张表放上面这张就足够说明问题。4.4 实验报告里体现“惩罚项效果”的曲线逻辑回归的第二个验证点是用实际数据测试最常见的路径是去 UCI 找一个二分类数据集比如成人收入或银行营销数据。但 UCI 数据字段较多处理起来要写编码和缺失值填充很多人在这一步被卡住。更稳妥的做法是在合成数据上先做多项式特征扩展再对比无惩罚和有惩罚两种设置的测试准确率。from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import make_pipeline # 带 L2 的逻辑回归 pipeline make_pipeline( PolynomialFeatures(degree5, include_biasFalse), LogisticRegression(penaltyl2, C0.1, solverlbfgs) ) pipeline.fit(X_train, y_train) print(L2 acc:, pipeline.score(X_test, y_test))PolynomialFeatures 将 2 个特征扩展到 5 阶后变成 20 维左右特征复杂了无惩罚模型会开始过拟合训练准确率接近 1 而测试准确率下降加 L2 后测试准确率能回升几个点。报告中画出“degree-准确率”曲线横轴取 1 到 9纵轴取测试准确率两条曲线分别对应开惩罚和不开惩罚这是最能说明正则化价值的图。注意 C 和 λ 是倒数关系C 越小惩罚越强在 sklearn 的网格搜索里通常设置C 1/λ。5. 考前自查与报告写作技巧如何把实验报告变成加分项5.1 实验报告必须有的四张图一份逻辑回归实验报告老师通常不会逐行读代码而是看图表是否能支撑结论。第一张是损失下降曲线横轴迭代轮数纵轴训练损失无惩罚和 L2 惩罚各一条第二张是合成数据上的决策边界可视化把背景网格上的预测概率用等高线画出来第三张是多项式拟合正弦函数的阶数对比3 阶、7 阶、15 阶各画一条直观展示欠拟合、拟合和过拟合第四张是朴素贝叶斯和逻辑回归在同一 GMM 数据上的准确率对比柱状图。四张图对应的代码都来自前面章节整理顺序后直接嵌入报告即可。5.2 参数调节学习率、λ 和多项式阶数的联动参数之间不是独立的。多项式阶数升高特征尺度急剧变大如果不对特征做标准化梯度下降的学习率必须调得很小才能稳定否则损失直接爆掉。L2 惩罚可以缓解高阶特征带来的方差但 λ 也不能盲目加大λ 太大决策边界退化成直线λ 太小过拟合仍在。一个可复现的自检流程是先把 degree 固定在 5跑通代码再对学习率做 0.5、0.1、0.01 三档衰减最后把 C 在 1e-3 到 1e2 之间取对数网格画出验证集准确率选择峰值对应的 C。这段逻辑可以直接写进报告的“参数讨论”小节。5.3 从课程设计到广告点击率预测的实际迁移如果还想多拿一点工程分把实验里的人造数据换成 UCI 的实际二分类数据集训练完成后用分类报告收尾from sklearn.metrics import classification_report, confusion_matrix pred pipeline.predict(X_test) print(confusion_matrix(y_test, pred)) print(classification_report(y_test, pred))混淆矩阵比准确率更细能看出模型在少数类上的表现classification_report里的 precision、recall、f1-score 三个字段与广告点击率预测这类不平衡场景直接对应点击率通常只有百分之几准确率没有参考价值这时重点看 recall 和 F1。压缩包里附的期末题也覆盖了逻辑回归推导、GMM 与朴素贝叶斯关系、多项式拟合过拟合分析三类题目考前一天把这些图和结论对照着过一遍比重新翻课件更接近考点。用上面这段代码跑一遍实验把曲线和混淆矩阵整理进报告分数往往比只贴源码高一个档位。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价