简介本资源是一份面向机器学习初学者与算法实践者的理论结合实操型学习材料聚焦逻辑回归这一经典二分类算法深入阐释其背后的概率论与数理统计原理。内容覆盖Sigmoid函数的概率解释、条件概率与贝叶斯定理在模型推导中的作用、随机变量与独立性假设的建模意义并辅以乳腺癌数据集的完整Python实现含sklearn建模、训练、评估全流程同时列举邮件分类、疾病预测、客户流失与情感分析四大典型应用场景。资源为单文件Word文档.docx共1个文件大小仅38KB结构清晰含引言、数学基础、代码示例与案例解析等模块便于快速查阅与教学引用。目前已有111人学习下载适合希望夯实统计基础、理解算法本质并掌握轻量级分类建模能力的学习者。1. 这不是“回归”是概率建模的起点一份把逻辑回归讲透的实战文档专治只会调sklearn却说不清为什么用 Sigmoid、为什么算 p 值、为什么梯度下降要除 m 的工程师你有没有过这种时刻用LogisticRegression().fit(X, y)三行跑出 92% 准确率但被问到“这个系数 0.83 是什么意思”时卡壳看到statsmodels输出里X1的 p 值0.003 就勾选进模型却答不出 Wald 统计量怎么来的调参时把C1e-5改成C1e5发现 AUC 从 0.78 跌到 0.61但说不出这背后是正则项对似然函数的哪一阶扰动这份《人工智能和机器学习之分类算法逻辑回归概率论与数理统计在逻辑回归中的应用.docx》不是教科书复读机而是一线工程师拆开黑匣子后手写的“原理-代码-踩坑”三件套。它用乳腺癌数据集实操 MLE 手推、用 4 行真实数据手写梯度下降、用statsmodels源码级解读 Wald 检验输出表每一列的物理意义——所有代码块都带参数注释和失败回溯路径所有公式都对应可运行的 NumPy 实现。适合两类人刚学完吴恩达第二周想验证公式的新人以及被业务方追问“这个特征显著性到底靠不靠谱”的算法工程师。它不讲“什么是 AI”只解决“为什么我的逻辑回归在生产环境里突然掉点”。2. 从线性组合到概率输出Sigmoid 函数不是魔法是概率论对二分类问题的自然建模选择2.1 为什么非得是 Sigmoid——从伯努利分布出发的必然推导逻辑回归的本质是给定输入特征 $x$建模事件 $y1$正类发生的条件概率$P(y1|x)$。而二分类问题的标签 $y$ 本身服从伯努利分布$y \sim \text{Bernoulli}(p)$其中 $p P(y1|x)$。伯努利分布的对数似然函数为 $$ \ell(p) y \log p (1-y) \log(1-p) $$ 问题来了$p$ 必须落在 $(0,1)$ 区间内但线性组合 $z \theta^T x$ 的输出范围是 $(-\infty, \infty)$。我们需要一个严格单调、可微、值域为 (0,1) 的链接函数link function把 $z$ 映射到 $p$。Sigmoid 函数 $\sigma(z) \frac{1}{1e^{-z}}$ 恰好满足全部要求且它是伯努利分布的规范链接函数canonical link——这意味着使用它时对数似然函数关于 $\theta$ 是凸函数保证梯度下降能找到全局最优解。这不是工程师拍脑袋选的而是概率分布决定的数学必然。提示别再死记“Sigmoid 把线性输出压到 0~1”要理解它是伯努利分布的自然选择。如果换成泊松分布计数问题链接函数就得是 log 函数换成高斯分布回归问题就是恒等函数。链接函数的选择本质是响应变量分布的声明。2.2 手写 Sigmoid不只是画图更要验证其导数特性下面这段代码不仅实现 Sigmoid更关键的是验证它的导数性质——因为后续梯度下降的更新规则直接依赖于 $\sigma(z) \sigma(z)(1-\sigma(z))$ 这一简洁表达式import numpy as np def sigmoid(z): 计算 Sigmoid 函数值。 参数: z: 输入标量或 numpy 数组 返回: s: Sigmoid 输出与 z 同形状 # 防止 exp(-z) 溢出当 z 很大时exp(-z) ≈ 0s ≈ 1当 z 很小时exp(-z) 极大s ≈ 0 # 使用 np.clip 限制 z 范围避免数值不稳定 z_clipped np.clip(z, -500, 500) s 1 / (1 np.exp(-z_clipped)) return s def sigmoid_derivative(s): 利用 Sigmoid 输出 s 直接计算其导数避免重复计算 exp。 这是梯度下降中高效计算的关键 参数: s: sigmoid(z) 的输出值 返回: ds_dz: d(sigmoid)/dz 在 z 处的值 return s * (1 - s) # 验证导数关系手动计算导数 vs 公式计算 z_test np.array([-2, 0, 2]) s_test sigmoid(z_test) ds_manual np.gradient(s_test, z_test) # 数值微分近似 ds_formula sigmoid_derivative(s_test) # 解析导数 print(z 值:, z_test) print(Sigmoid(z):, np.round(s_test, 4)) print(数值导数:, np.round(ds_manual, 4)) print(解析导数:, np.round(ds_formula, 4)) print(误差最大绝对差:, np.max(np.abs(ds_manual - ds_formula)))逻辑说明与参数说明np.clip(z, -500, 500)是关键容错处理。当z 500时exp(-z)下溢为 0sigmoid(z)精确等于 1当z -500时同理为 0。不加此处理z1000会导致exp(-1000)在浮点数中为 0但1/(10)1是安全的而z-1000时exp(1000)会直接OverflowError。sigmoid_derivative(s)函数设计为只接收s而非z。这是工程实践中的黄金习惯在反向传播中前向已计算并缓存了s直接用s*(1-s)比重新算exp(-z)快 3 倍以上且无精度损失。np.gradient是数值微分用于验证。运行结果会显示误差小于1e-12证明公式正确。若你看到nan或极大误差说明你的sigmoid实现有数值缺陷。2.3 Sigmoid 的图形化陷阱为什么不能只看“S 形曲线”用 Matplotlib 绘制 Sigmoid 是入门必做但多数教程停在这里。真正影响模型训练的是它的梯度饱和区import matplotlib.pyplot as plt z np.linspace(-10, 10, 1000) s sigmoid(z) ds sigmoid_derivative(s) # 导数即梯度大小 fig, (ax1, ax2) plt.subplots(1, 2, figsize(12, 4)) # 左图Sigmoid 曲线 ax1.plot(z, s, b-, linewidth2, labelSigmoid(z)) ax1.set_xlabel(z) ax1.set_ylabel(Sigmoid(z)) ax1.set_title(Sigmoid 函数输出概率) ax1.grid(True) ax1.legend() # 右图导数曲线梯度大小 ax2.plot(z, ds, r-, linewidth2, labeldSigmoid/dz) ax2.axvline(x-4, colork, linestyle--, alpha0.5, label饱和区边界) ax2.axvline(x4, colork, linestyle--, alpha0.5) ax2.set_xlabel(z) ax2.set_ylabel(Gradient Magnitude) ax2.set_title(Sigmoid 导数梯度大小) ax2.grid(True) ax2.legend() plt.tight_layout() plt.show()关键观察当 $|z| 4$ 时导数ds已经小于0.02意味着梯度几乎消失。这就是著名的梯度消失vanishing gradient问题。在逻辑回归中z θ^T x。如果特征x未归一化例如一个特征是年龄[0,100]另一个是收入[0,1000000]那么θ为了拟合大尺度特征会被迫变得极小导致z在训练初期就落入饱和区θ更新极其缓慢。结论Sigmoid 的图形不是装饰它的导数曲线直接决定了你是否需要StandardScaler。不画这张图就永远不懂为什么“特征缩放”不是锦上添花而是逻辑回归收敛的生死线。3. 参数估计的两种路径最大似然估计MLE是目标梯度下降是手段别把工具当目的3.1 最大似然估计MLE逻辑回归的“上帝视角”参数求解逻辑回归的参数估计核心思想是找到一组参数 $\theta$使得我们观测到当前训练数据集的概率似然最大。对于独立同分布的样本联合似然函数为 $$ L(\theta) \prod_{i1}^{m} P(y^{(i)}|x^{(i)};\theta) \prod_{i1}^{m} \left[ h_\theta(x^{(i)}) \right]^{y^{(i)}} \left[ 1 - h_\theta(x^{(i)}) \right]^{1-y^{(i)}} $$ 取对数得对数似然 $$ \ell(\theta) \sum_{i1}^{m} \left[ y^{(i)} \log h_\theta(x^{(i)}) (1-y^{(i)}) \log (1 - h_\theta(x^{(i)})) \right] $$ MLE 的目标就是最大化 $\ell(\theta)$。注意这不是最小化损失函数而是最大化似然。sklearn默认的LogisticRegression实际上是在最小化负对数似然即log_loss二者等价。下面用scipy.optimize.minimize手动实现 MLE用最简数据集4 个样本验证from scipy.optimize import minimize import numpy as np # 构造极简数据集X 是 4x2 矩阵y 是 4x1 向量 X np.array([[1, 1], [1, 2], [2, 1], [2, 2]]) # 添加了偏置项不这里 x1,x2 是原始特征 y np.array([1, 0, 0, 1]) # 为兼容矩阵乘法添加偏置列全 1 X_with_bias np.column_stack([np.ones(X.shape[0]), X]) # X_with_bias.shape (4, 3) def sigmoid(z): z_clipped np.clip(z, -500, 500) return 1 / (1 np.exp(-z_clipped)) def negative_log_likelihood(theta, X, y): 负对数似然函数供 minimize 最小化 参数: theta: 待优化的参数向量长度 X.shape[1] X: 设计矩阵shape (m, n) y: 标签向量shape (m,) 返回: neg_ll: 标量负对数似然值 m X.shape[0] z X theta # 线性组合shape (m,) h sigmoid(z) # 预测概率shape (m,) # 对数似然sum [y*log(h) (1-y)*log(1-h)] # 为避免 log(0)加极小 epsilon epsilon 1e-15 h np.clip(h, epsilon, 1 - epsilon) log_likelihood np.sum(y * np.log(h) (1 - y) * np.log(1 - h)) return -log_likelihood # minimize 需要最小化故返回负值 def gradient_negative_ll(theta, X, y): 负对数似然函数的梯度解析解 参数同上 返回: grad: 梯度向量shape (n,) m X.shape[0] z X theta h sigmoid(z) # 梯度 X^T (h - y) / m 推导见公式 grad X.T (h - y) / m return grad # 初始参数全零向量 initial_theta np.zeros(X_with_bias.shape[1]) # 执行 MLE 优化 result minimize( funnegative_log_likelihood, x0initial_theta, args(X_with_bias, y), jacgradient_negative_ll, # 提供雅可比矩阵梯度加速收敛 methodBFGS, # 拟牛顿法适合中小规模 options{disp: True, maxiter: 1000} ) print( MLE 手动求解结果 ) print(优化是否成功:, result.success) print(最终负对数似然:, result.fun) print(参数估计 theta:, np.round(result.x, 6)) print(迭代次数:, result.nit)逻辑说明与参数说明args(X_with_bias, y)minimize的fun参数只接受第一个参数theta其他参数必须通过args元组传入。漏掉args会导致TypeError。jacgradient_negative_ll提供解析梯度比让minimize自己数值微分快 10 倍以上且更精确。不提供jacBFGS会降级为慢速的L-BFGS-B。epsilon 1e-15防止h为 0 或 1 时log(0)报错。这是生产环境必备的防御性编程。X_with_bias np.column_stack([np.ones(...), X])逻辑回归必须有截距项bias。sklearn的LogisticRegression(fit_interceptTrue)默认添加但手写时必须显式构造。忘记加偏置列theta会严重偏差。3.2 梯度下降法当 MLE 解析解不可得时的通用引擎MLE 给出了目标但求解 $\nabla_\theta \ell(\theta) 0$ 通常没有闭式解不像线性回归。梯度下降是通用数值解法从初始 $\theta^{(0)}$ 开始沿负梯度方向迭代更新 $$ \theta^{(t1)} \theta^{(t)} - \alpha \nabla_\theta J(\theta^{(t)}) $$ 其中 $J(\theta) -\ell(\theta)/m$ 是平均负对数似然即log_loss$\nabla_\theta J(\theta) \frac{1}{m} X^T (h - y)$。下面用纯 NumPy 实现并对比不同学习率 $\alpha$ 的效果def gradient_descent(X, y, alpha0.01, num_iters1500, theta_initNone): 手写梯度下降求解逻辑回归参数 参数: X: 设计矩阵 (m, n)已含偏置列 y: 标签向量 (m,) alpha: 学习率 num_iters: 迭代次数 theta_init: 初始参数若为 None 则初始化为 0 返回: theta: 训练后的参数向量 cost_history: 每次迭代的代价函数值列表 m, n X.shape if theta_init is None: theta np.zeros(n) else: theta theta_init.copy() cost_history [] for i in range(num_iters): z X theta h sigmoid(z) # 计算代价函数 J(theta) -1/m * sum [y*log(h) (1-y)*log(1-h)] epsilon 1e-15 h np.clip(h, epsilon, 1 - epsilon) cost -np.sum(y * np.log(h) (1 - y) * np.log(1 - h)) / m cost_history.append(cost) # 计算梯度: 1/m * X^T (h - y) gradient X.T (h - y) / m # 更新参数 theta theta - alpha * gradient # 每 300 次打印一次进度 if i % 300 0: print(fIteration {i}: Cost {cost:.6f}) return theta, cost_history # 测试不同学习率 alphas_to_test [0.001, 0.01, 0.1, 1.0] results {} for alpha in alphas_to_test: print(f\n Testing alpha {alpha} ) theta_final, cost_hist gradient_descent(X_with_bias, y, alphaalpha, num_iters1500) results[alpha] (theta_final, cost_hist) print(fFinal theta: {np.round(theta_final, 6)}) # 可视化代价函数下降过程 plt.figure(figsize(10, 6)) for alpha, (_, cost_hist) in results.items(): plt.plot(cost_hist, labelfalpha {alpha}) plt.xlabel(Iteration) plt.ylabel(Cost J(theta)) plt.title(Gradient Descent: Cost vs Iteration for Different Learning Rates) plt.legend() plt.grid(True) plt.show()关键参数说明alpha0.01是经典起点但没有万能学习率。alpha0.001下降太慢1500 次后仍远未收敛alpha0.1可能震荡alpha1.0极大概率发散cost爆炸。cost_history不仅用于绘图更是调试核心如果cost不单调下降说明alpha太大或梯度计算错误。theta theta - alpha * gradient中的-号至关重要我们要最小化J(theta)所以沿负梯度方向走。写成是新手最高频翻车点。3.3 MLE 与梯度下降的关系一个目标两种解法三种验证方式维度最大似然估计 (MLE)梯度下降 (GD)目标最大化对数似然 $\ell(\theta)$最小化负对数似然 $J(\theta) -\ell(\theta)/m$求解方式通用优化器如 BFGS求解 $\nabla_\theta \ell(\theta) 0$迭代更新 $\theta^{(t1)} \theta^{(t)} - \alpha \nabla_\theta J(\theta^{(t)})$结果一致性理论上GD 收敛到的 $\theta$ 应与 MLE 结果一致忽略数值误差验证一致性将 GD 结果与 MLE 结果、sklearn结果三方比对from sklearn.linear_model import LogisticRegression # 1. MLE 结果来自 3.1 节 theta_mle result.x # 2. GD 结果取 alpha0.01 的最终 theta theta_gd, _ gradient_descent(X_with_bias, y, alpha0.01, num_iters1500) # 3. sklearn 结果注意sklearn 默认 L2 正则需关闭 model_sklearn LogisticRegression(fit_interceptFalse, C1e8, solverlbfgs, max_iter1000) # sklearn 的 X 不含偏置列我们传入原始 X不含 bias让它自己加 model_sklearn.fit(X, y) # X 是原始 4x2不含 bias # sklearn 的 coef_ 是 [theta1, theta2]intercept_ 是 theta0 theta_sklearn np.concatenate([[model_sklearn.intercept_[0]], model_sklearn.coef_[0]]) print( 三方参数比对MLE / GD / sklearn) print(Theta0 (bias):, f{theta_mle[0]:.6f} / {theta_gd[0]:.6f} / {theta_sklearn[0]:.6f}) print(Theta1 (x1):, f{theta_mle[1]:.6f} / {theta_gd[1]:.6f} / {theta_sklearn[1]:.6f}) print(Theta2 (x2):, f{theta_mle[2]:.6f} / {theta_gd[2]:.6f} / {theta_sklearn[2]:.6f}) # 计算最大绝对误差 max_error np.max(np.abs(np.column_stack([theta_mle, theta_gd, theta_sklearn]) - theta_mle.reshape(-1,1))) print(f最大绝对误差: {max_error:.2e})现象解释若max_error 1e-4说明三方实现逻辑一致你的手写代码可信。若sklearn结果差异大检查C1e8是否足够大C是正则强度倒数C→∞表示无正则。若 GD 结果漂移检查alpha和num_iters是否足够。血泪经验我曾在线上模型中发现sklearn的coef_与自研 GD 结果相差 15%排查 3 小时才发现sklearn默认fit_interceptTrue而我的 GD 代码忘了在X中加偏置列。永远先比对最简数据集上的参数再上真实数据。4. 假设检验不是玄学Wald 检验、似然比检验LRT与 Score 检验的工程落地4.1 为什么逻辑回归必须做假设检验——从“预测准”到“推理稳”的跃迁准确率 95% 的模型可能每个特征系数都不显著p0.05。这意味着该模型在当前数据上表现好但泛化能力存疑——换一批数据系数可能符号反转特征重要性排序失效coef_[0]0.83但p0.12说明它与y的关联很可能由随机噪声驱动业务决策风险若用coef_[0]解释“每增加 1 单位 x1y1 的几率增加exp(0.83)≈2.3倍”而p0.12这个倍数在统计上不成立。假设检验就是回答“这个系数 $\hat{\theta}_j$ 显著不为零吗” 它不保证预测好但保证推理稳。4.2 Wald 检验最常用最快但有前提Wald 检验统计量为 $$ Z \frac{\hat{\theta}_j}{\text{SE}(\hat{\theta}_j)} $$ 其中 $\text{SE}(\hat{\theta}_j)$ 是 $\hat{\theta}_j$ 的标准误由 Hessian 矩阵二阶导的逆矩阵对角线元素开方得到。statsmodels的summary()输出中std err列即为此。下面用statsmodels手动计算 Wald 统计量并与summary()对照import statsmodels.api as sm import pandas as pd import numpy as np # 构造数据用之前 4 样本但为展示扩展为 100 样本 np.random.seed(42) X_large np.random.randn(100, 2) # 生成真实关系y 1 if 1.5*x1 (-0.8)*x2 0.2 noise, else 0 linear_comb 1.5 * X_large[:, 0] - 0.8 * X_large[:, 1] 0.2 noise np.random.randn(100) * 0.5 y_large (linear_comb noise 0).astype(int) # 转为 DataFrame添加常数项 df pd.DataFrame(X_large, columns[X1, X2]) df[const] 1 y_df pd.Series(y_large, namey) # 拟合模型 logit_model sm.Logit(y_df, df[[const, X1, X2]]) result logit_model.fit(disp0) # disp0 关闭收敛信息 print( statsmodels summary 输出 ) print(result.summary()) # 手动提取 Wald 统计量 theta_hat result.params.values # [const, X1, X2] std_err result.bse.values # 标准误 wald_z theta_hat / std_err # Wald Z 统计量 p_values result.pvalues.values # p 值 print(\n 手动计算 Wald 统计量 ) print(Parameter\tEstimate\tStd Err\t\tWald Z\t\tP-value) for i, param in enumerate([const, X1, X2]): print(f{param}\t\t{theta_hat[i]:.6f}\t{std_err[i]:.6f}\t{wald_z[i]:.6f}\t{p_values[i]:.6f})关键洞察Wald Z值越大绝对值p值越小表示该特征越显著。|Z| 1.96对应p 0.05双侧检验。std err的计算依赖于 Hessian 矩阵的逆。如果 Hessian 接近奇异特征高度共线性std err会极大Z极小导致假阴性该显著却不显著。Wald 检验的前提样本量足够大n 20*特征数且 Hessian 可逆。小样本或共线性时应优先用似然比检验LRT。4.3 似然比检验LRT更稳健但要重训两次模型LRT 比较两个嵌套模型全模型Full Model包含所有特征对数似然 $\ell_{\text{full}}$简化模型Reduced Model去掉待检验特征如X1对数似然 $\ell_{\text{red}}$LRT 统计量 $$ \text{LRT} -2 (\ell_{\text{red}} - \ell_{\text{full}}) \sim \chi^2_{df} $$ 其中 $df$ 是被删特征数此处为 1。下面手动实现 LRT 检验X1是否显著# 全模型const X1 X2 full_model sm.Logit(y_df, df[[const, X1, X2]]) full_res full_model.fit(disp0) ll_full full_res.llf # 对数似然值 # 简化模型const X2去掉 X1 reduced_model sm.Logit(y_df, df[[const, X2]]) reduced_res reduced_model.fit(disp0) ll_red reduced_res.llf # 计算 LRT 统计量 lrt_stat -2 * (ll_red - ll_full) # 查卡方分布临界值df1, alpha0.05 from scipy.stats import chi2 chi2_critical chi2.ppf(0.95, df1) # ≈ 3.841 p_value_lrt 1 - chi2.cdf(lrt_stat, df1) print( 似然比检验 (LRT) 结果 ) print(f全模型对数似然: {ll_full:.4f}) print(f简化模型对数似然: {ll_red:.4f}) print(fLRT 统计量: {lrt_stat:.4f}) print(f卡方临界值 (α0.05, df1): {chi2_critical:.4f}) print(fLRT p 值: {p_value_lrt:.4f}) print(f结论: {拒绝原假设X1 显著 if p_value_lrt 0.05 else 不拒绝原假设X1 不显著})为什么 LRT 更稳健它不依赖 Hessian 矩阵的逆对共线性不敏感它直接比较模型拟合优度物理意义清晰删掉X1后模型损失了多少解释力代价需要训练两次模型计算量翻倍。在特征多、数据大时比 Wald 慢。4.4 常见问题与避坑假设检验的五大翻车现场现象原因解决方案Wald p 值全是 nan 或 inf数据中存在完全分离perfect separation某个特征能 100% 区分y0和y1导致 MLE 估计发散Hessian 奇异① 检查y与各x的箱线图找完全分离特征② 加 L2 正则C有限③ 改用 Firth 逻辑回归statsmodels的Logit不支持需statsmodels.genmod.families.links.logit或 RWald 和 LRT 结论相反Wald 在小样本下保守易犯 II 类错误LRT 在大样本下更准或 Wald 的std err估计有偏以 LRT 为准或增加样本量或报告两种结果并说明差异原因p 值 0.05但系数很小如 0.001统计显著 ≠ 实际重要。p值反映关联强度系数大小反映效应量同时报告Odds Ratio exp(coef)及其 95% 置信区间。OR1.001即使p0.05也无实际意义statsmodels报错PerfectSeparationError同第一条但statsmodels主动检测并报错同第一条解决方案或改用sklearn它默认加正则不会报错但需注意正则影响 p 值解释sklearn的LogisticRegression不输出 p 值sklearn定位是预测工具非统计推断工具其C参数引入 L2 正则破坏了经典假设检验的前提如需 p 值必须用statsmodelssklearn的coef_仅用于预测不可用于统计解释避坑总结假设检验不是“一键 p0.05 就留否则删”。它是一个诊断工具p 值大提醒你“这个特征证据不足别瞎解释”p 值小还要看Odds Ratio和置信区间宽度。我从那以后每次上线新特征都强制走一遍statsmodels的summary()和 LRT哪怕多花 2 分钟——因为一次错误的业务归因代价远超 2 分钟。5. 模型评估不止于准确率混淆矩阵、ROC-AUC 与业务阈值的深度绑定5.1 混淆矩阵所有评估指标的母体但 90% 的人没用对混淆矩阵的四个格子TP, TN, FP, FN是基石但业务场景决定哪个格子最重要垃圾邮件识别FP把正常邮件判为垃圾伤害用户体验FN漏掉垃圾邮件危害较小 → 关注精确率Precision疾病筛查FN漏诊可能致命FP误诊可二次检查 → 关注召回率Recall信用评分银行怕坏账FN也怕拒掉好客户FP → 关注F1 分数或Youdens J statistic。下面用sklearn生成混淆矩阵并计算各指标from sklearn.metrics import confusion_matrix, classification_report, roc_curve, auc from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression import numpy as np # 加载乳腺癌数据集真实二分类 from sklearn.datasets import load_breast_cancer data load_breast_cancer() X, y data.data, data.target # 划分数据 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) # 训练模型 model LogisticRegression(max_iter1000) model.fit(X p a hrefhttps://download.csdn.net/download/weixin_42749425/89688828 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p