【机器学习】逻辑回归(LogisticRegression)分类鸢尾花

该博客介绍了逻辑回归中的sigmoid函数及其性质,解释了为何不使用线性回归的代价函数,并展示了如何通过梯度下降优化代价函数。此外,讨论了一对多方法用于解决多元分类问题,以鸢尾花数据集为例,实现逻辑回归进行分类。最后,给出了代码实现和预测结果。

1.介绍

1.1 sigmoid函数

逻辑回归中的sigmoid函数:
g(θ0+θ1X1+⋯θnXn)=h(θX)=p=eθX1+eθX g(θ_0+θ_1X_1+\cdotsθ_nX_n)=h(θX)=p=\frac{e^{θX}}{1+e^{θX}} g(θ0+θ1X1+θnXn)=h(θX)=p=1+eθXeθX
也可写成(分子分母同时除以eθX):
g(θ0+θ1X1+⋯θnXn)=h(θX)=p=11+e−θX g(θ_0+θ_1X_1+\cdotsθ_nX_n)=h(θX)=p=\frac{1}{1+e^{-θX}} g(θ0+θ1X1+θnXn)=h(θX)=p=1+eθX1

得到的sigmoid函数图像为:

在这里插入图片描述

可知,当θX>=0,即θ01X1+…+θnXn>=0时,p>=0.5,预测y=1

当θX<0,即θ01X1+…+θnX<0时,p<0.5,预测y=0

1.2 代价函数

为什么不使用像线性回归那样的代价函数?

如图,因为所得到的代价函数为非凸函数,会有很多个局部最优解,使用梯度下降时不一定能够收敛到全局最小值。
在这里插入图片描述

sigmoid函数:
hθ(x)=11+e−θx h_\theta(x)=\frac{1}{1+e^{-\theta x}} hθ(x)=1+eθx1

因此,采用如下的代价函数:
在这里插入图片描述

写在一起如下:
在这里插入图片描述

使用梯度下降求θ:

在这里插入图片描述

∂J(θ)∂θj=(hθ(x)−y)xj \frac{\partial J(\theta)}{\partial\theta_j}= (h_\theta(x)-y)x_j θjJ(θ)=(hθ(x)y)xj
可得:
θj:=θj−α∑i=1m(hθ(x)(i)−y(i))xj(i) \theta_j:=\theta_j-\alpha\sum_{i=1}^m(h_\theta(x)^{(i)}-y^{(i)})x_j^{(i)} θj:=θjαi=1m(hθ(x)(i)y(i))xj(i)
其中i表示第几个样本,j表示第几个特征值

1.3 多元分类:一对多

思想:将多个类别分成独立的二元问题,然后分别求出各个分类的代价函数,再将测试集的数据代入所获得的结果中,取结果最大的预测概率,就能判断出这个数据属于哪一个类别。

在这里插入图片描述

使用逻辑回归将鸢尾花数据进行分类。鸢尾花数据为3类,属于多元分类问题。可以将其分解成多个二元问题,即对于每个类别,进行模型训练得到模型,然后对于测试集中的每个数据,使用得到的参数对其进行计算,得到的最大值即为这个数据属于的类别。

2.代码

"""

@Author: sanshui
@Time:2021/11/15 15:15
@Software: PyCharm
"""

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import classification_report


def get_data():
    """
    获取数据集
    :return:
    """
    iris = load_iris()

    return iris.data, iris.target


def split_data(data, target):
    """
    划分数据集
    :param data:
    :param target:
    :return:
    """
    data = np.array(data)
    target = np.array(target)
    target = np.reshape(target, (target.shape[0], 1))

    # 正则化数据,防止数据大小本身对结果造成影响
    sd = StandardScaler()
    data = sd.fit_transform(data)

    # 拼接特征值与类别
    dataset = np.hstack((data, target))
    n = dataset.shape[0]

    # 打乱数据
    np.random.shuffle(dataset)

    # 划分数据集,返回训练集与测试集
    train = dataset[:int(0.7 * n), :]
    test = dataset[int(0.7 * n):, :]

    return train, test


def sigmoid(z):
    """
    sigmoid函数
    :param z:
    :return:
    """
    return 1 / (1 + np.exp(-z))


def draw_sigmoid():
    """
    画出sigmoid函数
    :return:
    """
    fig, ax = plt.subplots()
    x_data = np.arange(-10, 10, 0.1)
    ax.plot(x_data, sigmoid(x_data))
    plt.show()


def calCost(dataset, theta):
    """
    计算代价函数
    :param dataset:
    :param theta:
    :return:
    """
    x = dataset[:, :-1]
    y = dataset[:, -1:]
    z = x @ theta.T
    # 训练数据个数,或者用m = y.shape[1]
    m = y.size
    para1 = np.multiply(-y, np.log(sigmoid(z)))
    para2 = np.multiply((1 - y), np.log(1 - sigmoid(z)))
    # 代价函数Y
    J = 1 / m * np.sum(para1 - para2)
    return J


def gradient(dataset, theta, iters, alpha):
    """
    梯度下降
    :param dataset:
    :param theta:
    :param iters:
    :param alpha:
    :return:
    """
    # 存放每次梯度下降后的损失值
    x = dataset[:, :-1]
    y = dataset[:, -1:]
    for i in range(iters):
        h_x = sigmoid(x @ theta.T)
        theta = theta - alpha / len(x) * (h_x - y).T @ x
    return theta


def get_per_classify_data(data, i):
    """
    返回第i类的数据
    :param data:数据集
    :param i:类别
    :return:
    """
    return data[data[:, -1] == i]


def get_final_theta(data, i, theta, iters, alpha):
    """
    获取梯度下降后的theta值
    :param data:
    :param i:
    :param theta:
    :param iters:
    :param alpha:
    :return:
    """
    dataset = get_per_classify_data(data, i)
    return gradient(dataset, theta, iters, alpha)


def predict(dataset, theta_list):
    """
    预测结果
    :param dataset:
    :param theta_list:
    :return:
    """
    x = dataset[:, :-1]
    per_theta_list = [i[0] for i in theta_list]
    per_theta_list = np.array(per_theta_list)

    per_prob = sigmoid(np.dot(x, per_theta_list.T))

    # 返回每行最大值所在的索引,即概率最大的类别
    return np.argmax(per_prob, axis=1)


if __name__ == '__main__':
    plt.rcParams['font.sans-serif'] = 'SimHei'  # 黑体
    plt.rcParams['axes.unicode_minus'] = False  # 显示负号

    data, target = get_data()
    train, test = split_data(data, target)
    draw_sigmoid()

    iters = 1000 # 迭代次数
    alpha = 0.5 # 学习率
    theta_list = []
    for i in range(data.shape[1]):
        theta = np.zeros((1, data.shape[1]))
        theta_list.append(theta)

    final_theta_list = []
    target_list = list(set(target))

    for i in target_list:
        theta_i = get_final_theta(train, i, theta_list[target_list.index(i)], iters, alpha)
        final_theta_list.append(theta_i)

    y_predict = predict(test, final_theta_list)

    # 查看预测准确度
    print(classification_report(y_predict, test[:, -1]))

3 预测结果

在这里插入图片描述

### 使用逻辑回归鸢尾花数据集进行分类 #### 数据预处理 在实现逻辑回归之前,需要加载并准备鸢尾花数据集。该数据集包含三个类别(Setosa、Versicolor 和 Virginica),每种类别有 50 条记录,总共有 150 行和 4 列特征变量(Sepal Length、Sepal Width、Petal Length 和 Petal Width)。由于标准逻辑回归适用于二元分类问题[^2],因此需要将三类问题转换为多个二元分类子问题。 一种常见的方法是一对多策略(One-vs-Rest, OvR),即针对每个类别分别构建一个二元分类器[^1]。例如: - 类别 Setosa 对抗其他两类; - 类别 Versicolor 对抗其他两类; - 类别 Virginica 对抗其他两类。 通过这种方式,最终可以通过比较各个分类器的概率输出来预测属于哪个类别。 #### 实现过程 以下是基于 Python 的逻辑回归实现代码: ```python import numpy as np from sklearn.datasets import load_iris 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 # 加载数据集 data = load_iris() X = data.data y = data.target # 将数据标准化 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X_scaled, y, test_size=0.3, random_state=42 ) # 初始化逻辑回归模型,默认采用 One-vs-Rest 方法 model = LogisticRegression(multi_class='ovr', solver='liblinear') # 训练模型 model.fit(X_train, y_train) # 预测 y_pred = model.predict(X_test) # 输出性能指标 print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}") print("\nClassification Report:") print(classification_report(y_test, y_pred)) ``` 此代码实现了以下功能: 1. **数据加载与分割**:使用 `train_test_split` 函数划分训练集和测试集。 2. **特征缩放**:为了提高收敛速度和稳定性,使用 `StandardScaler` 对输入特征进行了标准化[^3]。 3. **模型初始化与训练**:调用了 Scikit-Learn 中的 `LogisticRegression` 模型,并指定参数使其支持多分类任务。 4. **评估模型表现**:利用准确率 (`accuracy`) 及详细的分类报告 (`classification_report`) 展示模型效果。 #### 结果解释 运行以上脚本后会得到如下结果: - Accuracy 显示整体正确率; - Classification Report 提供更细致的信息,包括 Precision、Recall 和 F1-Score 等评价指标[^4]。 这些指标能够帮助理解模型对于每一类别的识别能力以及是否存在某些特定类型的偏差或不足之处。 --- #### 注意事项 当面对不平衡的数据分布情况时,仅依赖于单一准确性衡量可能无法全面反映实际情况。此时应综合考量多种评估手段,比如混淆矩阵 (Confusion Matrix),ROC 曲线下的面积 (AUC-ROC) 或者 PR 曲线下面积等高级工具[^4]。 此外,在实际应用过程中还可以尝试调整正则化强度 C 值或者更换优化算法 Solver 参数以进一步提升泛化能力和鲁棒性[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步一点丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值