逻辑回归分类(LogisticRegression)算法详解

本文介绍了 scikit-learn 的 LogisticRegression 逻辑回归分类算法。虽然名称中带有“回归”,但它本质上是一个经典的分类模型,主要用于二分类任务,同时也能够扩展到多分类问题。文章将从算法原理、主要参数、代码示例、可视化分析以及适用场景几个方面展开,帮助读者系统理解 LogisticRegressionscikit-learn 中的使用方式与实践价值。


1. 算法背景

逻辑回归(Logistic Regression)是机器学习中最基础、最常用的监督学习算法之一。它的核心思想是:先对输入特征进行线性组合,再通过一个概率映射函数将输出压缩到 01 之间,从而得到样本属于某一类别的概率。由于这一输出结果具有明确的概率意义,因此逻辑回归不仅适合做分类任务,也常用于风险预测、转化分析、医疗诊断和金融风控等实际场景。

scikit-learn 中,逻辑回归由 sklearn.linear_model.LogisticRegression 实现。该模型具有实现简单、训练高效、可解释性较强等优点,在很多分类问题中都可以作为首选的基线模型。虽然逻辑回归结构简单,但在工程实践中依然具有非常重要的地位,尤其适合用来快速验证数据是否具有较好的线性可分性。


2. 逻辑回归的基本原理

逻辑回归的出发点仍然是线性模型。对于输入样本 xxx,模型首先计算一个线性组合:

z=w1x1+w2x2+⋯+wnxn+b z = w_1x_1 + w_2x_2 + \cdots + w_nx_n + b z=w1x1+w2x2++wnxn+b

其中,www 表示各个特征对应的权重,bbb 表示偏置项。这个线性结果本身只是一个实数,并不能直接表示类别概率,因此逻辑回归进一步引入了 Sigmoid 函数:

σ(z)=11+e−z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+ez1

经过 Sigmoid 映射之后,输出值就落在 01 之间,可以理解为样本属于正类的概率。通常情况下,当该概率大于 0.5 时,模型预测为正类;反之则预测为负类。

从决策边界的角度来看,逻辑回归学习到的本质上仍然是线性边界,因此它更适合处理线性可分或近似线性可分的数据。如果数据的真实边界非常复杂,逻辑回归的表达能力就会受到限制。

在模型训练过程中,逻辑回归并不是通过最小化均方误差来学习参数,而是通过最小化对数损失函数完成优化。为了降低过拟合风险,实际实现中通常还会结合正则化机制,使模型在训练集和测试集之间具备更好的泛化能力。


3. scikit-learn 中的 LogisticRegression

scikit-learn 中,逻辑回归的基本使用方式非常直接:

from sklearn.linear_model import LogisticRegression

# 创建逻辑回归模型
model = LogisticRegression()

# 使用训练集拟合模型
model.fit(X_train, y_train)

# 对测试集进行预测
y_pred = model.predict(X_test)

虽然调用形式看起来非常简单,但在实际建模过程中,逻辑回归通常不会单独使用,而是会和数据划分、特征标准化、模型评估以及可视化分析一起构成完整流程。特别是在数值型特征量纲差异较大的场景中,标准化往往会显著改善模型训练效果和收敛稳定性,因此这是逻辑回归实践中非常重要的一步。


4. 主要参数解析

scikit-learn 中,LogisticRegression 的常见构造形式如下:

from sklearn.linear_model import LogisticRegression

LogisticRegression(
    penalty='l2',          # 正则化类型:l1/L2/elasticnet/none,用于防止过拟合
    *,
    dual=False,            # 对偶/原始形式求解,仅适用于l2正则+liblinear,样本数<特征数时用True
    tol=0.0001,            # 停止迭代的精度阈值,损失函数变化小于该值则提前收敛
    C=1.0,                 # 正则化强度的倒数,值越小正则化越强
    fit_intercept=True,    # 是否拟合截距(偏置项b),False则模型无截距
    intercept_scaling=1,   # 仅solver=liblinear时有效,截距的缩放系数
    class_weight=None,     # 类别权重,balanced自动根据样本数量平衡权重
    random_state=None,     # 随机种子,保证多次运行结果可复现
    solver='lbfgs',        # 优化算法:lbfgs/liblinear/newton-cg/sag/saga
    max_iter=100,          # 最大迭代次数,不收敛时可适当调大
    multi_class='deprecated', # 多分类方式,已废弃,由库自动处理
    verbose=0,             # 日志输出详细程度,0不输出,越大输出越多
    warm_start=False,      # 是否热启动,True则复用上次训练结果继续迭代
    n_jobs=None,           # 并行运算CPU核数,None=1,-1=使用全部CPU
    l1_ratio=None,         # 弹性网(elasticnet)混合比例,0=L2,1=L1,仅penalty=elasticnet时使用
)

虽然 LogisticRegression 提供了较多参数,但在实际使用中,最值得关注的通常还是 penaltyCsolvermax_iterclass_weight

penalty 用于指定正则化方式,常见取值包括 l2l1elasticnetNone。其中,l2 是最常见也最稳定的选择;l1 可以得到更稀疏的系数结果,在一定程度上具有特征选择作用;elasticnet 则结合了 l1l2 的特点。

C 表示正则化强度的倒数。C 越小,正则化越强,模型越简单;C 越大,正则化越弱,模型越倾向于拟合训练数据。实际调参时,C 往往是最核心的参数之一。

solver 表示优化算法。默认的 lbfgs 适合大多数中小规模数据;liblinear 更适合小规模数据,并支持 l1 正则;saga 则适合更大规模数据,同时支持 elasticnet。因此,penaltysolver 通常需要结合起来考虑。

max_iter 表示最大迭代次数,默认值为 100。如果模型训练时出现未收敛警告,通常可以适当增大这个参数。在实际示例中,常将它设置为 1000,以减少迭代次数不足带来的影响。

class_weight 用于设置类别权重,默认值为 None。当数据集存在明显类别不平衡时,可以设置为 'balanced',让模型根据类别分布自动调整权重,从而减轻多数类对训练过程的影响。

除上述参数外,fit_intercept 用于控制是否拟合截距项,通常保持默认值 True 即可;random_state 用于固定随机种子,便于实验复现;l1_ratio 只在 penalty='elasticnet' 时才有意义。至于 dualintercept_scalingverbosewarm_startn_jobs 等参数,在一般教学和常规建模中并不是优先关注的重点。

总体来看,掌握 penaltyCsolvermax_iterclass_weight 这几个核心参数,已经足以应对大多数逻辑回归建模场景。


5. 二分类实战示例

下面以 scikit-learn 自带的乳腺癌数据集为例,演示逻辑回归的完整建模流程。案例包括数据加载、数据集分布观察、训练集和测试集划分、特征标准化、模型训练、预测评估以及可视化分析。

5.1 导入库并加载数据

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 设置主题
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})

# 加载乳腺癌数据集
data = load_breast_cancer()
X = data.data
y = data.target

# 输出数据基本信息
print("特征维度:", X.shape)
print("类别名称:", data.target_names)
print("类别分布:", np.bincount(y))

特征维度: (569, 30)
类别名称: [‘malignant’ ‘benign’]
类别分布: [212 357]

5.2 二分类 类别分布可视化

# 将目标变量整理为 DataFrame,便于使用 seaborn 作图
target_df = pd.DataFrame({
    "类别": y
})

# 绘制类别分布图
plt.figure(figsize=(7, 5))
sns.countplot(data=target_df, x="类别")
plt.title("乳腺癌数据集类别分布")
plt.xlabel("类别")
plt.ylabel("样本数量")
plt.tight_layout()
plt.show()

在这里插入图片描述

从类别分布图可以看出,该数据集中的两类样本数量并不完全一致,但整体差异并不算特别极端。这说明在本例中,模型可以先从默认设置开始训练,而不必一开始就对类别权重做过多干预。

5.3 划分训练集与测试集并进行标准化

# 划分训练集和测试集,并保持类别比例一致
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 对特征进行标准化处理
scaler = StandardScaler()
X_train_std = scaler.fit_transform(X_train)
X_test_std = scaler.transform(X_test)

5.4 构建并训练模型

# 创建逻辑回归模型
model = LogisticRegression(
    penalty='l2',
    C=1.0,
    solver='lbfgs',
    max_iter=1000,
    random_state=42
)

# 在标准化后的训练集上拟合模型
model.fit(X_train_std, y_train)

5.5 模型预测与评估

# 进行类别预测和概率预测
y_pred = model.predict(X_test_std)
y_prob = model.predict_proba(X_test_std)[:, 1]

# 输出模型评估结果
print("准确率:", accuracy_score(y_test, y_pred))
print("混淆矩阵:")
print(confusion_matrix(y_test, y_pred))
print("分类报告:")
print(classification_report(y_test, y_pred, target_names=data.target_names))

准确率: 0.9824561403508771

混淆矩阵:
[[41 1]
​ [ 1 71]]

分类报告:
                ​ precision   recall   f1-score   support
malignant         0.98    0.98         0.98           42
benign              0.99    0.99         0.99           72
accuracy                   0.98          114

macro avg        0.98    0.98         0.98          114
weighted avg    0.98    0.98         0.98          114

准确率可以帮助我们快速了解模型整体表现,而分类报告则进一步给出了精确率、召回率和 F1 值等指标。对于分类模型来说,仅仅看准确率往往还不够,还需要结合混淆矩阵进一步分析模型在哪些类别上更容易出现误判。

5.6 二分类 混淆矩阵热力图

# 计算混淆矩阵
cm = confusion_matrix(y_test, y_pred)

# 绘制热力图
plt.figure(figsize=(7, 5))
ax = sns.heatmap(
    cm,
    annot=True,
    fmt="d",
    cmap="Blues",
    xticklabels=data.target_names,
    yticklabels=data.target_names
)
plt.xlabel("预测类别")
plt.ylabel("真实类别")
plt.title("乳腺癌逻辑回归混淆矩阵热力图")

plt.tight_layout()
plt.show()

在这里插入图片描述

从混淆矩阵热力图可以更直观地看到模型分类结果的分布情况。热力图对角线上的数值表示被正确分类的样本数量,而非对角线上的数值则表示误分类样本。从图中通常可以观察到,大部分样本都集中在对角线位置,这说明逻辑回归在该数据集上的整体分类效果较好。与此同时,少量非对角线元素则揭示了模型仍然存在一定的混淆情况,这对于进一步优化模型具有参考价值。

5.7 特征系数可视化

# 将模型系数与特征名称整理到同一个表中
coef_df = pd.DataFrame({
    "特征": data.feature_names,
    "系数": model.coef_[0]
})

# 计算系数绝对值并筛选前 10 个重要特征
coef_df["系数绝对值"] = coef_df["系数"].abs()
top_coef_df = coef_df.sort_values("系数绝对值", ascending=False).head(10)

# 绘制条形图
plt.figure(figsize=(8, 6))
ax = sns.barplot(data=top_coef_df, x="系数", y="特征")
plt.title("逻辑回归前10重要特征系数")
plt.xlabel("系数值")
plt.ylabel("特征名称")

plt.tight_layout()
plt.show()

在这里插入图片描述

逻辑回归的一个重要优势在于模型具有较好的可解释性。通过特征系数条形图,可以观察哪些特征对最终分类结果影响更大。系数为正通常表示该特征增大时,样本更倾向于被预测为正类;系数为负则表示该特征增大时,更倾向于被预测为负类;而绝对值越大,通常说明该特征对决策边界的影响越明显。由于这里已经对特征做了标准化,因此不同特征系数之间的对比更具有参考意义。


6. 二维数据下的分类边界可视化

为了更直观地理解逻辑回归“线性分类器”的本质,下面构造一个二维分类数据集,并使用散点图展示样本分布情况。

6.1 导入库并构造二维数据

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.datasets import make_classification
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})

# 生成二维二分类样本
X_vis, y_vis = make_classification(
    n_samples=300,
    n_features=2,
    n_redundant=0,
    n_informative=2,
    n_clusters_per_class=1,
    random_state=42
)

# 整理为 DataFrame 便于可视化
vis_df = pd.DataFrame(X_vis, columns=["特征1", "特征2"])
vis_df["类别"] = y_vis

6.2 样本分布可视化

# 绘制二维样本散点图
plt.figure(figsize=(7, 5))
sns.scatterplot(
    data=vis_df,
    x="特征1",
    y="特征2",
    hue="类别",
    palette="Set1"
)
plt.title("二维样本类别分布")
plt.xlabel("特征1")
plt.ylabel("特征2")
plt.tight_layout()
plt.show()

在这里插入图片描述

从散点图可以看出,两类样本在二维空间中呈现出较明显的分离趋势。这类数据非常适合逻辑回归建模,因为它本身更倾向于学习一条线性决策边界。如果样本分布呈现非常复杂的曲线状边界,那么逻辑回归的表达能力通常就会受到限制。

6.3 训练二维逻辑回归模型并绘制决策区域

# 对二维样本进行标准化
scaler_vis = StandardScaler()
X_vis_std = scaler_vis.fit_transform(X_vis)

# 训练二维逻辑回归模型
model_vis = LogisticRegression()
model_vis.fit(X_vis_std, y_vis)

# 构建网格点,用于绘制分类区域
x_min, x_max = X_vis_std[:, 0].min() - 1, X_vis_std[:, 0].max() + 1
y_min, y_max = X_vis_std[:, 1].min() - 1, X_vis_std[:, 1].max() + 1

xx, yy = np.meshgrid(
    np.linspace(x_min, x_max, 300),
    np.linspace(y_min, y_max, 300)
)

# 对网格点进行预测
grid = np.c_[xx.ravel(), yy.ravel()]
Z = model_vis.predict(grid).reshape(xx.shape)

# 整理标准化后的样本点
plot_df = pd.DataFrame({
    "特征1": X_vis_std[:, 0],
    "特征2": X_vis_std[:, 1],
    "类别": y_vis
})

# 绘制决策区域与样本散点
plt.figure(figsize=(8, 6))
plt.contourf(xx, yy, Z, alpha=0.25, cmap="coolwarm")
sns.scatterplot(
    data=plot_df,
    x="特征1",
    y="特征2",
    hue="类别",
    palette="Set1",
    edgecolor="black"
)
plt.title("逻辑回归决策边界示意图")
plt.xlabel("特征1")
plt.ylabel("特征2")

plt.tight_layout()
plt.show()

在这里插入图片描述

从决策区域图可以更清楚地看到,逻辑回归最终学习到的是一条线性分界面。图中不同背景区域表示模型对不同类别的预测范围,而散点则是真实样本的位置分布。当样本大体可以用直线分开时,逻辑回归通常能够取得较好的效果;反之,如果样本之间呈现复杂非线性混杂关系,那么逻辑回归就可能出现明显欠拟合。


7 正则化参数对模型的影响

在逻辑回归中,C 参数直接影响正则化强度,因此也会影响模型复杂度和泛化能力。下面通过一个简单实验,观察不同 C 值下模型表现的变化。

7.1 导入库并计算不同 C 值下的准确率

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

# 设置主题
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})

# 加载乳腺癌数据集
data = load_breast_cancer()

# 转成 DataFrame
df = pd.DataFrame(data.data, columns=data.feature_names)
df["target"] = data.target

# 特征和标签
X = df.drop("target", axis=1)
y = df["target"]

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 标准化
scaler = StandardScaler()
X_train_std = scaler.fit_transform(X_train)
X_test_std = scaler.transform(X_test)

# 定义不同的 C 值
C_values = [0.01, 0.1, 1, 10, 100]
score_list = []

# 分别训练模型并记录准确率
for c in C_values:
    model_c = LogisticRegression(C=c, max_iter=1000, random_state=42)
    model_c.fit(X_train_std, y_train)
    y_pred_c = model_c.predict(X_test_std)
    score_list.append(accuracy_score(y_test, y_pred_c))

# 整理结果
result_df = pd.DataFrame({
    "C值": C_values,
    "准确率": score_list
})

print(result_df)

        C值       准确率
0      0.01   0.964912
1      0.10   0.982456
2      1.00   0.973684
3    10.00   0.973684
4  100.00   0.938596

7.2 使用折线图观察参数变化趋势

# 绘制折线图
plt.figure(figsize=(7.5, 5.2))
ax = sns.lineplot(
    data=result_df,
    x="C值",
    y="准确率",
    marker="o",
    linewidth=2.2,
    markersize=7
)

# 设置对数坐标轴
plt.xscale("log")
plt.title("正则化强度 C 对逻辑回归准确率的影响", fontsize=14, pad=12)
plt.xlabel("C值(对数尺度)", fontsize=11)
plt.ylabel("准确率", fontsize=11)

# 设置网格样式
ax.grid(True, linestyle="--", alpha=0.45)

# 单独设置刻度字体,避免对数轴刻度显示问题
fp = FontProperties(family="DejaVu Sans")
for label in ax.get_xticklabels():
    label.set_fontproperties(fp)
for label in ax.get_yticklabels():
    label.set_fontproperties(fp)

plt.tight_layout()
plt.show()

在这里插入图片描述

从折线图中可以更直观地观察 C 对模型性能的影响。通常来说,当 C 较小时,正则化更强,模型会更简单,因此可能降低过拟合风险,但也可能因为过于保守而出现欠拟合;当 C 较大时,模型的拟合能力增强,但同时也可能带来泛化能力下降的风险。实际建模时,往往需要结合交叉验证来进一步寻找更合适的参数取值,而不是仅仅依赖单次测试结果。


8. 多分类任务中的逻辑回归

逻辑回归不仅适用于二分类问题,也可以用于多分类任务。下面以鸢尾花数据集为例,展示逻辑回归在多分类问题中的应用效果。

8.1 导入库并加载鸢尾花数据集

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from matplotlib.lines import Line2D
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

# 设置主题
sns.set_theme(style="whitegrid", font="SimHei", rc={"axes.unicode_minus": False})

# 加载鸢尾花数据集
iris = load_iris()
X_iris = iris.data
y_iris = iris.target

# 定义中文类别名称
iris_label_names = ["山鸢尾", "变色鸢尾", "维吉尼亚鸢尾"]
iris_label_map = {
    0: "山鸢尾",
    1: "变色鸢尾",
    2: "维吉尼亚鸢尾"
}

# 整理为 DataFrame
iris_df = pd.DataFrame(X_iris, columns=iris.feature_names)
iris_df["类别"] = y_iris
iris_df["类别名称"] = iris_df["类别"].map(iris_label_map)

在这里插入图片描述

8.2 多分类 类别分布可视化

# 绘制类别分布图
plt.figure(figsize=(7, 5))
sns.countplot(
    data=iris_df,
    x="类别名称",
    order=iris_label_names
)
plt.title("鸢尾花数据集类别分布")
plt.xlabel("类别名称")
plt.ylabel("样本数量")
plt.tight_layout()
plt.show()

从类别分布图可以看到,鸢尾花数据集中的三个类别分布较为均衡,这使得它非常适合作为多分类模型的教学示例。在这种相对理想的数据条件下,模型的训练和评估通常更容易体现算法本身的能力,而不会过多受到类别不平衡问题的干扰。

8.3 模型训练与评估

# 划分训练集和测试集
X_train_iris, X_test_iris, y_train_iris, y_test_iris = train_test_split(
    X_iris, y_iris, test_size=0.2, random_state=42, stratify=y_iris
)

# 对特征进行标准化
scaler_iris = StandardScaler()
X_train_iris_std = scaler_iris.fit_transform(X_train_iris)
X_test_iris_std = scaler_iris.transform(X_test_iris)

# 训练逻辑回归模型
model_iris = LogisticRegression(max_iter=1000)
model_iris.fit(X_train_iris_std, y_train_iris)

# 进行预测并输出评估结果
y_pred_iris = model_iris.predict(X_test_iris_std)

print("准确率:", accuracy_score(y_test_iris, y_pred_iris))
print(classification_report(y_test_iris, y_pred_iris, target_names=iris_label_names))

准确率: 0.9333333333333333

​                        precision    recall    f1-score   support
            山鸢尾        1.00      1.00          1.00          10
        变色鸢尾         0.90      0.90          0.90          10
 维吉尼亚鸢尾         0.90      0.90          0.90          10

​        accuracy                                       0.93          30
​     macro avg         0.93       0.93          0.93          30
​ weighted avg         0.93       0.93         0.93          30

8.4 多分类 混淆矩阵热力图

# 计算混淆矩阵
cm_iris = confusion_matrix(y_test_iris, y_pred_iris)

# 绘制热力图
plt.figure(figsize=(7, 5))
ax = sns.heatmap(
    cm_iris,
    annot=True,
    fmt="d",
    cmap="Blues",
    xticklabels=iris_label_names,
    yticklabels=iris_label_names
)
plt.xlabel("预测类别")
plt.ylabel("真实类别")
plt.title("鸢尾花逻辑回归混淆矩阵热力图")

plt.tight_layout()
plt.show()

在这里插入图片描述

从多分类混淆矩阵热力图中可以看出,不同类别之间的预测结果分布情况更加清晰。如果某两个类别在特征空间中较为接近,那么模型更容易在这两类之间产生混淆。通过这样的可视化,读者不仅可以看到整体准确率,还可以进一步理解模型在具体类别层面的表现差异。

8.5 真实类别与预测结果的 PCA 单图对比

# 对整个鸢尾花数据集进行标准化
X_iris_std = StandardScaler().fit_transform(X_iris)

# 使用 PCA 将四维特征降到二维
pca = PCA(n_components=2)
X_iris_pca = pca.fit_transform(X_iris_std)

# 使用训练好的模型对全部样本进行预测
y_pred_all = model_iris.predict(X_iris_std)

# 构建可视化数据表
pca_df = pd.DataFrame({
    "主成分1": X_iris_pca[:, 0],
    "主成分2": X_iris_pca[:, 1],
    "真实类别": y_iris,
    "预测类别": y_pred_all
})

# 添加中文类别名称和预测是否正确标记
pca_df["真实类别名称"] = pca_df["真实类别"].map(iris_label_map)
pca_df["预测类别名称"] = pca_df["预测类别"].map(iris_label_map)
pca_df["预测是否正确"] = np.where(
    pca_df["真实类别"] == pca_df["预测类别"],
    "预测正确",
    "预测错误"
)

# 自定义颜色
palette = {
    "山鸢尾": "#4C72B0",
    "变色鸢尾": "#DD8452",
    "维吉尼亚鸢尾": "#55A868"
}

# 创建画布
fig, ax = plt.subplots(figsize=(10.5, 7.5))

# 按预测是否正确分组
correct_df = pca_df[pca_df["预测是否正确"] == "预测正确"]
wrong_df = pca_df[pca_df["预测是否正确"] == "预测错误"]

# 绘制预测正确的样本
sns.scatterplot(
    data=correct_df,
    x="主成分1",
    y="主成分2",
    hue="真实类别名称",
    hue_order=iris_label_names,
    palette=palette,
    s=85,
    edgecolor="white",
    linewidth=0.9,
    alpha=0.9,
    ax=ax,
    legend=False
)

# 绘制预测错误的样本
sns.scatterplot(
    data=wrong_df,
    x="主成分1",
    y="主成分2",
    hue="真实类别名称",
    hue_order=iris_label_names,
    palette=palette,
    marker="X",
    s=140,
    edgecolor="black",
    linewidth=1.1,
    alpha=0.95,
    ax=ax,
    legend=False
)

# 设置标题与坐标轴
ax.set_title("鸢尾花数据集真实类别与逻辑回归预测结果对比图", fontsize=16, pad=14)
ax.set_xlabel("主成分1", fontsize=12)
ax.set_ylabel("主成分2", fontsize=12)
ax.grid(True, linestyle="--", linewidth=0.8, alpha=0.6)

# 构造“真实类别”图例
class_handles = [
    Line2D([0], [0], marker='o', color='w', label='山鸢尾',
           markerfacecolor=palette["山鸢尾"], markeredgecolor='white', markersize=10),
    Line2D([0], [0], marker='o', color='w', label='变色鸢尾',
           markerfacecolor=palette["变色鸢尾"], markeredgecolor='white', markersize=10),
    Line2D([0], [0], marker='o', color='w', label='维吉尼亚鸢尾',
           markerfacecolor=palette["维吉尼亚鸢尾"], markeredgecolor='white', markersize=10)
]

legend1 = ax.legend(
    handles=class_handles,
    title="真实类别",
    title_fontsize=12,
    fontsize=11,
    loc="upper right",
    frameon=True,
    fancybox=True,
    borderpad=0.8,
    labelspacing=0.6
)

# 构造“预测结果”图例
result_handles = [
    Line2D([0], [0], marker='o', color='w', label='预测正确',
           markerfacecolor='gray', markeredgecolor='white', markersize=9),
    Line2D([0], [0], marker='X', color='w', label='预测错误',
           markerfacecolor='gray', markeredgecolor='black', markersize=10)
]

legend2 = ax.legend(
    handles=result_handles,
    title="预测结果",
    title_fontsize=12,
    fontsize=11,
    loc="lower right",
    frameon=True,
    fancybox=True,
    borderpad=0.8,
    labelspacing=0.6
)

# 美化图例边框与透明度
legend1.get_frame().set_alpha(0.88)
legend1.get_frame().set_edgecolor("#CCCCCC")
legend1.get_frame().set_linewidth(0.8)

legend2.get_frame().set_alpha(0.88)
legend2.get_frame().set_edgecolor("#CCCCCC")
legend2.get_frame().set_linewidth(0.8)

# 将第一个图例重新添加到坐标轴上
ax.add_artist(legend1)

plt.tight_layout()
plt.show()

在这里插入图片描述

为了在同一张图中同时展示真实类别分布与模型预测效果,这里采用“颜色表示真实类别、点形状表示预测结果是否正确”的方式进行可视化,并将图例拆分为“真实类别”和“预测结果”两个部分。这样不仅能够保留 PCA 二维投影下各类别的整体分布情况,也可以更清晰地观察模型在哪些区域预测正确、哪些区域更容易发生误分类。

从图中可以看出,山鸢尾样本大多集中在左侧独立区域,并且几乎都被正确分类,说明逻辑回归对这一类别具有较好的识别能力。而变色鸢尾与维吉尼亚鸢尾在中部和右侧区域存在一定重叠,因此错误样本主要分布在两类交界附近。这说明逻辑回归在类别边界较清晰时表现稳定,而在类别分布存在交叉时更容易产生混淆。


9. 逻辑回归的优点与局限性

逻辑回归最大的优点在于模型结构清晰、实现简单、训练效率高,并且能够直接输出概率结果。对于很多实际业务问题来说,这种“简单但稳定”的模型往往更容易落地。尤其是在需要较强可解释性的任务中,逻辑回归通常比复杂的黑盒模型更容易被接受。

不过,逻辑回归的局限性同样十分明显。由于它本质上仍然是线性模型,因此在面对复杂的非线性关系时,往往难以准确刻画数据分布。如果数据的真实边界非常复杂,那么决策树、随机森林、支持向量机或神经网络等模型通常会有更强的表达能力。此外,逻辑回归对特征工程的依赖也较强,是否标准化、是否处理共线性、是否引入交互特征,都会直接影响模型最终表现。


10. 适用场景

从实际应用来看,逻辑回归非常适合作为分类任务中的基础模型。一方面,它训练速度快,能够快速建立基线结果;另一方面,它输出清晰、可解释性较强,便于分析不同特征对预测结果的影响。因此,在很多中小规模数据集上,逻辑回归依然是值得优先尝试的选择。

它常见于用户流失预测、信用风险评估、文本情感分类、广告点击率预测以及医疗辅助诊断等任务中。即使在后续需要引入更复杂模型时,逻辑回归也通常会作为一个重要的对照模型存在。


11. 总结

scikit-learn 中的 LogisticRegression 是一个经典而实用的分类算法。它基于线性组合与 Sigmoid 概率映射完成分类任务,在二分类和多分类问题中都具有广泛应用价值。该模型不仅训练速度快,而且具备较强的可解释性,同时还能通过正则化机制控制过拟合风险,因此在实际机器学习项目中经常被作为首选基线模型。

本文围绕逻辑回归的基本原理、主要参数、二分类实战、多分类示例以及可视化分析进行了系统介绍。特别是在案例部分,通过 sns.countplotsns.scatterplotsns.heatmapsns.barplotsns.lineplot 和 PCA 对比图等方式,能够更直观地观察数据分布、分类效果、特征影响以及参数变化趋势,这也更符合技术博客系列文章中“代码 + 图示 + 解释”的写作风格。

总体来看,逻辑回归虽然结构简单,但并不意味着它能力有限。相反,正是由于它简单、稳定、易解释,才使得它在大量实际问题中始终保持着重要地位。对于学习 scikit-learn 的读者来说,逻辑回归既是理解分类模型的重要起点,也是进一步学习线性模型、概率模型和正则化方法的重要基础。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐