文章参考于

笔者只是对其中的代码做了较为详细的注释,便于初学者理解

与线性回归不同,Logistic 回归没有封闭解。但由于损失函数是凸函数,因此我们可以使用梯度下降法来训练模型。事实上,在保证学习速率足够小且使用足够的训练迭代步数的前提下,梯度下降法(或任何其他优化算法)可以是能够找到全局最小值。

第0步:用 0 (或小的随机值)来初始化权重向量和偏置值

第 1 步:计算输入的特征与权重值的线性组合,这可以通过矢量化和矢量传播来对所有训练样本进行处理:a = X*w + b,其中 X 是所有训练样本的维度矩阵

第 2 步:用 sigmoid 函数作为激活函数,其返回值介于0到1之间:

逻辑回归代码python python逻辑回归模型建模步骤_机器学习


第 3 步:计算整个训练集的损失值。

我们希望模型得到的目标值概率落在 0 到 1 之间。因此在训练期间,我们希望调整参数,使得模型较大的输出值对应正标签(真实标签为 1),较小的输出值对应负标签(真实标签为 0 )。这在损失函数中表现为如下形式:

逻辑回归代码python python逻辑回归模型建模步骤_逻辑回归代码python_02


第 4 步:对权重向量和偏置量,计算其对损失函数的梯度。

一般形式如下:

逻辑回归代码python python逻辑回归模型建模步骤_数组_03


第 5 步:更新权重和偏置值。

逻辑回归代码python python逻辑回归模型建模步骤_机器学习_04


逻辑回归代码python python逻辑回归模型建模步骤_数组_05

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
np.random.seed(123) #seed( ) 用于指定随机数生成时所用算法开始的整数值,如果使用相同的seed( )值,则每次生成的随即数都相同,如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同

# We will perform logistic regression using a simple toy dataset of two classes
X, y_true = make_blobs(n_samples= 1000, centers=2)#sklearn中的make_blobs函数主要是为了生成数据集的,n_samples是待生成的样本总数,centers是类别数
#print(X.shape)  (1000, 2)

fig = plt.figure(figsize=(8,6))
plt.scatter(X[:,0], X[:,1], c=y_true)#x[:,0]是数组所有行的第一列数据,x[:,1]是数组所有行的第二列数据
plt.title("Dataset")
plt.xlabel("First feature")
plt.ylabel("Second feature")
plt.show()

# Reshape targets to get column vector with shape (n_samples, 1)
y_true = y_true[:, np.newaxis]#np.newaxis是增加维度的,相当于增加一列
# Split the data into a training and test set
X_train, X_test, y_train, y_test = train_test_split(X, y_true)
print(f'Shape X_train: {X_train.shape}')
print(f'Shape y_train: {y_train.shape}')
print(f'Shape X_test: {X_test.shape}')
print(f'Shape y_test: {y_test.shape}')


class LogisticRegression:

    def __init__(self): # 初始化
        pass # 什么也不做,只是防止语句出错

    def sigmoid(self, a): # 激活函数
        return 1 / (1 + np.exp(-a))

    def train(self, X, y_true, n_iters, learning_rate): # 训练样本,n_iters是迭代的次数
        """
        Trains the logistic regression model on given data X and targets y
        """
        # Step 0: Initialize the parameters
        n_samples, n_features = X.shape # shape返回的是维度,就是几行几列,是一个元组
        self.weights = np.zeros((n_features, 1)) # np.zeros返回来一个给定形状和类型的用0填充的数组,weights是指权重
        self.bias = 0 # bias 偏置赋值为0
        costs = [] # 损失数组

        for i in range(n_iters): # 迭代
            # Step 1 and 2: Compute a linear combination of the input features and weights,
            # apply the sigmoid activation function
            y_predict = self.sigmoid(np.dot(X, self.weights) + self.bias) # np.dot矩阵运算或向量内积

            # Step 3: Compute the cost over the whole training set.
            cost = (- 1 / n_samples) * np.sum(y_true * np.log(y_predict) + (1 - y_true) * (np.log(1 - y_predict)))

            # Step 4: Compute the gradients
            dw = (1 / n_samples) * np.dot(X.T, (y_predict - y_true))
            db = (1 / n_samples) * np.sum(y_predict - y_true)

            # Step 5: Update the parameters
            self.weights = self.weights - learning_rate * dw
            self.bias = self.bias - learning_rate * db

            costs.append(cost) # 将每个损失值添加进损失数组
            if i % 100 == 0: # 每过 100 次输出一下损失
                print(f"Cost after iteration {i}: {cost}")

        return self.weights, self.bias, costs

    def predict(self, X):
        """
        Predicts binary labels for a set of examples X.
        """
        y_predict = self.sigmoid(np.dot(X, self.weights) + self.bias)
        y_predict_labels = [1 if elem > 0.5 else 0 for elem in y_predict]

        return np.array(y_predict_labels)[:, np.newaxis]

regressor = LogisticRegression() # 创建逻辑回归实例
w_trained, b_trained, costs = regressor.train(X_train, y_train, n_iters=600, learning_rate=0.009)

fig = plt.figure(figsize=(8,6))
plt.plot(np.arange(600), costs) # 绘制的是随着训练的进行,损失值的变化,plt.plot(x, y):x为x轴数据, y为y轴数据,它可以绘制点和线, 并且对其样式进行控制
plt.title("Development of cost over training")
plt.xlabel("Number of iterations")
plt.ylabel("Cost")
plt.show()

y_p_train = regressor.predict(X_train)
y_p_test = regressor.predict(X_test)

print(f"train accuracy: {100 - np.mean(np.abs(y_p_train - y_train)) * 100}%") # mean()求取均值
print(f"test accuracy: {100 - np.mean(np.abs(y_p_test - y_test))}%")