【机器学习】梯度下降法:从底层手写实现线性回归

【机器学习】Building-Linear-Regression-from-Scratch

  • 线性回归 Linear Regression
    • 0. 数据的导入与相关预处理
    • 0.工具函数
    • 1. 批量梯度下降法 Batch Gradient Descent
    • 2. 小批量梯度下降法 Mini Batch Gradient Descent(在批量方面进行了改进)
    • 3. 自适应梯度下降法 Adagrad(在学习率方面进行了改进)
    • 4. 多变量线性回归 Multivariate Linear Regression(在特征方面进行了改进,拓展到多个特征)
    • 5. L1正则化 L1 Regularization(在正则化方面进行了改进)

This project is not about using ready-made libraries; it’s an exploration into the core principles that power linear regression. We start from basic mathematics and progressively build up to a fully functioning linear regression model. This hands-on approach is designed for learners and enthusiasts who want to deeply understand the intricacies of one of the most fundamental algorithms in machine learning. Dive in to experience linear regression like never before!

这个项目不是关于使用现成的库,而是对驱动线性回归的核心原则的一次探索。我们从基础数学开始,逐步构建出一个功能完善的线性回归模型。这种实践方法专为那些希望深入理解机器学习中最基本算法之一的复杂性的学习者和爱好者设计。深入体验前所未有的线性回归!

If you find the code helpful, please give me a Star.

如果觉得代码对你有帮助,请给我一个Star.

前往Github下载notebook
https://github.com/Zhu-Shatong/Building-Linear-Regression-from-Scratch

在这里插入图片描述

线性回归 Linear Regression

CopyRight: Zhu Shatong , Tongji University
本notebook所有算法均为手写,不使用任何库函数。

(算法设计部分)目录:

  1. 准备工作:数据的导入与相关预处理,相关工具函数的定义
  2. (单变量线性回归的)批量梯度下降法 Batch Gradient Descent
  3. 小批量梯度下降法 Mini Batch Gradient Descent(在批量方面进行了改进)
  4. 自适应梯度下降法 Adagrad(在学习率方面进行了改进)
  5. 多变量线性回归 Multivariate Linear Regression(在特征方面进行了改进,拓展到多个特征)
  6. L1正则化 L1 Regularization(也就是Lasso Regression,应对多变量的过拟合)

0. 数据的导入与相关预处理

在这一section, 我们将会负责导入数据,并对数据进行一些预处理,以便于后续的操作。

data:

我们首先导入的文件为 data.xlsx ,将它存储在data变量中。这个文件中包含了两列数据,分别为 xy

我们将会使用这些数据来进行线性回归的训练与可视化。

请注意,在后续本notebook中使用其他数据的时候,请勿再次命名为data。

数据来源:

Data on length-weight and length-length relationships, mean condition factor, and gonadosomatic index of Rutilus rutilus and Perca fluviatilis from the Ob River basin, Western Siberia - ScienceDirect

# 这一code block用来import需要的库

import pandas as pd  # 用来读取excel等文件
import random  # 用来进行随机打乱数据
import numpy as np  # 用来进行矩阵运算,应对多变量线性回归
# 这一code block用来读取数据

data = pd.read_excel("data.xlsx")  # 读取excel文件(单变量线性回归——测试文件)
# 这一code block用来对读取的数据进行一些处理

# 从数据框架中提取x和y值
x_values = data['x'].values
y_values = data['y'].values

0.工具函数

在这一section, 我们将会定义一些工具函数,以便于后续的操作。

目录:

  1. 可视化工具函数
  2. 线性回归模型计算
  3. 损失函数计算
# 可视化工具函数
# 对于数据点与拟合直线的可视化
def plot_data_and_line(x_values, y_values, theta_0_final, theta_1_final, cost_history, title):
    """
    Plot data points and the fitted line.
    
    :param x_values: 这是一个list,包含了所有的x值
    :param y_values: 这是一个list,包含了所有的y值
    :param theta_0_final: 这是一个float,表示最终的theta_0
    :param theta_1_final: 这是一个float,表示最终的theta_1
    :param cost_history: 这是一个list,包含了每一次迭代后的损失函数值
    :param title: 这是一个string,表示图像的标题
    :return: 返回一个图像
    """
    import matplotlib.pyplot as plt  # 用来画图

    plt.figure(figsize=(12, 5))

    # Subplot 1: Linear Regression
    # 这个subplot用来画出数据点和拟合直线
    plt.subplot(1, 2, 1)
    plt.scatter(x_values, y_values, color='blue', label='Original Data')  # 这里的scatter用来画出数据点
    plt.plot(x_values, [f_theta(x, theta_0_final, theta_1_final) for x in x_values], color='red',
             label='Linear Regression')  # 这里的列表表达式用来画出拟合直线
    plt.title(title)
    plt.xlabel('x')
    plt.ylabel('y')
    plt.legend()
    plt.grid(True)  # 显示网格

    # Subplot 2: Cost function history
    # 这个subplot用来画出损失函数的变化
    plt.subplot(1, 2, 2)
    plt.plot(cost_history, color='green')  # 这里的plot用来画出损失函数的变化
    plt.title('Cost Function History')
    plt.xlabel('Iteration')
    plt.ylabel('Cost')
    plt.grid(True)  # 显示网格

    plt.tight_layout()  # 调整子图之间的间距
    plt.show()

hypothesis:

f θ ( x ) = θ 0 + θ 1 x f_\theta(x)=\theta_0+\theta_1x fθ(x)=θ0+θ1x

def f_theta(x, theta_0, theta_1):
    """
    Linear regression model.
    
    :param x: 这是一个float,表示输入的x值
    :param theta_0: 这是一个float,表示theta_0
    :param theta_1: 这是一个float,表示theta_1
    :return: 这是一个float,表示预测值
    """
    return theta_0 + theta_1 * x

cost fuction:

J ( θ 0 , θ 1 ) = 1 2 N ∑ i = 1 N ( f θ ( x ( i ) ) − y ( i ) ) 2 J(\theta_0,\theta_1)=\frac1{2N}\sum_{i=1}^N(f_\theta(x^{(i)})-y^{(i)})^2 J(θ0,θ1)=2N1i=1N(fθ(x(i))y(i))2

def compute_cost(x_values, y_values, theta_0, theta_1):
    """
    Compute the cost function.
    
    :param x_values: 这是一个list,包含了所有的x值
    :param y_values: 这是一个list,包含了所有的y值
    :param theta_0: 这是一个float,表示theta_0
    :param theta_1: 这是一个float,表示theta_1
    :return: 这是一个float,表示损失函数的值
    """

    # 计算的公式为:J(theta_0, theta_1) = 1/2N * sum((f_theta(x_i) - y_i)^2)
    N = len(x_values)
    total_error = 0
    for i in range(len(x_values)):
        total_error += (f_theta(x_values[i], theta_0, theta_1) - y_values[i]) ** 2
    return total_error / (2 * N)

1. 批量梯度下降法 Batch Gradient Descent

repeat until convergence:

θ j : = θ j − α ∂ ∂ θ j J ( θ 0 , θ 1 ) ( for  j = 1  and  j = 0 ) \theta_j:=\theta_j-\alpha\frac{\partial}{\partial\theta_j}J(\theta_0,\theta_1) \\ (\text{for }j=1\text{ and }j=0) θj:=θjαθjJ(θ0,θ1)(for j=1 and j=0)

Repeat until convergence:

θ 0 : = θ 0 − a 1 N ∑ i = 1 N ( f θ ( x ( i ) ) − y ( i ) ) θ 1 : = θ 1 − a 1 N ∑ i = 1 N ( f θ ( x ( i ) ) − y ( i ) ) x ( i ) \begin{aligned}\theta_0{:}&=\theta_0-a\frac1N\sum_{i=1}^N(f_\theta\big(x^{(i)}\big)-y^{(i)})\\\theta_1{:}&=\theta_1-a\frac1N\sum_{i=1}^N(f_\theta\big(x^{(i)}\big)-y^{(i)})x^{(i)}\end{aligned} θ0:θ1:=θ0aN1i=1N(fθ(x(i))y(i))=θ1aN1i=1N(fθ(x(i))y(i))x(i)

def gradient_descent(x_values, y_values, alpha=0.05, convergence_threshold=1e-8, max_iterations=10000):
    """
    Perform gradient descent to learn theta_0 and theta_1.
    
    :param x_values: 这是一个list,包含了所有的x值
    :param y_values: 这是一个list,包含了所有的y值
    :param alpha: 这是一个float,表示学习率
    :param convergence_threshold: 这是一个float,表示收敛阈值
    :param max_iterations: 这是一个int,表示最大迭代次数
    :return: 这是一个tuple,包含了theta_0, theta_1, cost_history,分别表示最终的theta_0, theta_1和损失函数的变化
    """

    # 计算公式为: theta_j = theta_j - alpha * 1/N * sum((f_theta(x_i) - y_i) * x_i)

    theta_0 = 0  # 初始化theta_0
    theta_1 = 0  # 初始化theta_1
    N = len(x_values)  # 样本数量

    cost_history = []  # 用来保存损失函数的变化
    for _ in range(max_iterations):  # 进行迭代
        sum_theta_0 = 0  # 用来计算theta_0的梯度
        sum_theta_1 = 0  # 用来计算theta_1的梯度
        for i in range(N):
            error = f_theta(x_values[i], theta_0, theta_1) - y_values[i]  # 计算误差
            sum_theta_0 += error
            sum_theta_1 += error * x_values[i]
        # 注意,所有的theta的更新都是在同一时刻进行的
        theta_0 -= alpha * (1 / N) * sum_theta_0
        theta_1 -= alpha * (1 / N) * sum_theta_1
        cost_history.append(compute_cost(x_values, y_values, theta_0, theta_1))  # 计算损失函数的值

        if len(cost_history) > 1 and abs(cost_history[-1] - cost_history[-2]) < convergence_threshold:
            # 如果损失函数的变化小于收敛阈值,则停止迭代
            break

    return theta_0, theta_1, cost_history
# 这一code block用来调用上面的函数
theta_0_final, theta_1_final, cost_history = gradient_descent(x_values, y_values)

# 打印最终的theta_0, theta_1, cost
theta_0_final, theta_1_final, cost_history[-1]
# 这一code block用来画出数据点和拟合直线
plot_data_and_line(x_values, y_values, theta_0_final, theta_1_final, cost_history,
                   'Linear Regression using Gradient Descent')

在这里插入图片描述

2. 小批量梯度下降法 Mini Batch Gradient Descent(在批量方面进行了改进)

θ 0 : = θ 0 − a 1 N k ∑ i = 1 N k ( f θ ( x ( i ) ) − y ( i ) ) θ 1 : = θ 1 − a 1 N k ∑ i = 1 N k ( f θ ( x ( i ) ) − y ( i ) ) x ( i ) \begin{aligned}\theta_0&:=\theta_0-a\frac1{N_k}\sum_{i=1}^{N_k}(f_\theta\big(x^{(i)}\big)-y^{(i)})\\\theta_1&:=\theta_1-a\frac1{N_k}\sum_{i=1}^{N_k}(f_\theta\big(x^{(i)}\big)-y^{(i)})x^{(i)}\end{aligned} θ0θ1:=θ0aNk1i=1Nk(fθ(x(i))y(i)):=θ1aNk1i=1Nk(fθ(x(i))y(i))x(i)

def mini_batch_gradient_descent(x_values, y_values, batch_size=5, alpha=0.05, convergence_threshold=1e-8,
                                max_iterations=10000):
    """
    Perform mini batch gradient descent to learn theta_0 and theta_1.
    
    :param x_values:  这是一个list,包含了所有的x值
    :param y_values:  这是一个list,包含了所有的y值
    :param batch_size:  这是一个int,表示batch的大小
    :param alpha:  这是一个float,表示学习率
    :param convergence_threshold:  这是一个float,表示收敛阈值
    :param max_iterations:  这是一个int,表示最大迭代次数
    :return:  这是一个tuple,包含了theta_0, theta_1, cost_history,分别表示最终的theta_0, theta_1和损失函数的变化
    """

    theta_0 = 0  # 初始化theta_0
    theta_1 = 0  # 初始化theta_1
    N = len(x_values)
    cost_history = []

    for _ in range(max_iterations):
        # 对数据进行随机打乱
        combined = list(zip(x_values, y_values))  # 将x_values和y_values打包成一个list
        random.shuffle(combined)  # 对打包后的list进行随机打乱
        x_values[:], y_values[:] = zip(*combined)  # 将打乱后的list解包赋值给x_values和y_values

        # Mini-batch updates
        # 这里的代码与batch gradient descent的代码类似,只是多了一个batch_size的参数
        # 对于每一个batch,都会计算一次梯度,并更新theta_0和theta_1
        for i in range(0, N, batch_size):  # i从0开始,每次增加batch_size
            x_batch = x_values[i:i + batch_size]  # 从i开始,取batch_size个元素
            y_batch = y_values[i:i + batch_size]  # 从i开始,取batch_size个元素
            sum_theta_0 = 0  # 用来计算theta_0的梯度
            sum_theta_1 = 0  # 用来计算theta_1的梯度
            for j in range(len(x_batch)):  # 对于每一个batch中的元素
                error = f_theta(x_batch[j], theta_0, theta_1) - y_batch[j]
                sum_theta_0 += error
                sum_theta_1 += error * x_batch[j]
            theta_0 -= alpha * (1 / batch_size) * sum_theta_0
            theta_1 -= alpha * (1 / batch_size) * sum_theta_1
        cost_history.append(compute_cost(x_values, y_values, theta_0, theta_1))

        if len(cost_history) > 1 and abs(cost_history[-1] - cost_history[-2]) < convergence_threshold:
            # 如果损失函数的变化小于收敛阈值,则停止迭代
            break

    return theta_0, theta_1, cost_history
# 这一code block用来调用上面的函数

# K值的选择需要我们不断尝试与比较,来获取更好的效果
possible_K_values = [1, 3, 4, 5, 6, 7, 10]  # 可能得K值需要自己设定,对于不同的数据集,可能需要不同的K值
best_K = possible_K_values[0]
lowest_cost = float('inf')
theta_0_mini_batch = 0
theta_1_mini_batch = 0
cost_history_mini_batch = []

for K in possible_K_values:  # 对于每一个K值
    theta_0_temp, theta_1_temp, cost_history_temp = mini_batch_gradient_descent(x_values, y_values, K)
    if cost_history_temp[-1] < lowest_cost:  # 如果损失函数的值更小
        lowest_cost = cost_history_temp[-1]
        best_K = K
        theta_0_mini_batch = theta_0_temp
        theta_1_mini_batch = theta_1_temp
        cost_history_mini_batch = cost_history_temp

best_K, theta_0_mini_batch, theta_1_mini_batch, lowest_cost
# 这一code block用来画出数据点和拟合直线
plot_data_and_line(x_values, y_values, theta_0_mini_batch, theta_1_mini_batch, cost_history_mini_batch,
                   'Linear Regression using Mini Batch Gradient Descent, K= ' + str(best_K))

在这里插入图片描述

3. 自适应梯度下降法 Adagrad(在学习率方面进行了改进)

θ ( t + 1 ) : = θ ( t ) − a ∑ i = 0 t ( g ( i ) ) 2 g ( t ) \begin{aligned}\theta^{(\mathbf{t+1})}{:}=\theta^{(\mathbf{t})}-\frac{a}{\sqrt{\sum_{i=0}^{t}(g^{(i)})^2}}g^{(t)}\end{aligned} θ(t+1):=θ(t)i=0t(g(i))2 ag(t)
其中
g ( t ) = ∂ J ( θ ( t ) ) ∂ θ g^{(t)}=\frac{\partial J(\theta^{(t)})}{\partial\theta} g(t)=θJ(θ(t))

# 请注意这里的学习率,我将它设定的非常大,得益于adagrad的特性,我们可以使用更大的学习率
# 如果将学习率设定过小,会导致adagrad无法收敛,效果较差
# 所以,我们需要alpha也需要不断尝试与比较,来获取更好的效果
def adagrad_mini_batch_gradient_descent(x_values, y_values, batch_size=5, alpha=3, convergence_threshold=1e-8,
                                        max_iterations=10000):
    """
    Perform mini batch gradient descent with adaptive learning rate.
    
    :param x_values:  这是一个list,包含了所有的x值
    :param y_values:  这是一个list,包含了所有的y值
    :param batch_size:  这是一个int,表示batch的大小
    :param alpha:   这是一个float,表示学习率
    :param convergence_threshold:  这是一个float,表示收敛阈值
    :param max_iterations:  这是一个int,表示最大迭代次数
    :return:    这是一个tuple,包含了theta_0, theta_1, cost_history,分别表示最终的theta_0, theta_1和损失函数的变化
    """

    theta_0 = 0  # 初始化theta_0
    theta_1 = 0  # 初始化theta_1
    N = len(x_values)
    cost_history = []

    # 初始化sum_squared_gradients,这是用来计算学习率的
    sum_squared_gradients_0 = 0.0001  # 较小的值以避免被零除
    sum_squared_gradients_1 = 0.0001

    for _ in range(max_iterations):
        # 对数据进行随机打乱
        combined = list(zip(x_values, y_values))  # 将x_values和y_values打包成一个list
        random.shuffle(combined)  # 对打包后的list进行随机打乱
        x_values[:], y_values[:] = zip(*combined)  # 将打乱后的list解包赋值给x_values和y_values

        # Mini-batch updates
        # 这里的代码与batch gradient descent的代码类似,只是多了一个batch_size的参数
        for i in range(0, N, batch_size):
            x_batch = x_values[i:i + batch_size]
            y_batch = y_values[i:i + batch_size]
            sum_theta_0 = 0
            sum_theta_1 = 0
            for j in range(len(x_batch)):
                error = f_theta(x_batch[j], theta_0, theta_1) - y_batch[j]
                sum_theta_0 += error
                sum_theta_1 += error * x_batch[j]

            # 计算梯度
            # 计算公式为: theta_j = theta_j - alpha / (sum_squared_gradients_j ** 0.5) * 1/N * sum((f_theta(x_i) - y_i) * x_i)
            gradient_0 = (1 / batch_size) * sum_theta_0  # 计算theta_0的梯度
            gradient_1 = (1 / batch_size) * sum_theta_1  # 计算theta_1的梯度

            sum_squared_gradients_0 += gradient_0 ** 2  # 更新sum_squared_gradients_0
            sum_squared_gradients_1 += gradient_1 ** 2  # 更新sum_squared_gradients_1

            adaptive_alpha_0 = alpha / (sum_squared_gradients_0 ** 0.5)  # 计算theta_0的学习率
            adaptive_alpha_1 = alpha / (sum_squared_gradients_1 ** 0.5)  # 计算theta_1的学习率

            theta_0 -= adaptive_alpha_0 * gradient_0  # 更新theta_0
            theta_1 -= adaptive_alpha_1 * gradient_1  # 更新theta_1

        cost_history.append(compute_cost(x_values, y_values, theta_0, theta_1))

        if len(cost_history) > 1 and abs(cost_history[-1] - cost_history[-2]) < convergence_threshold:
            # 如果损失函数的变化小于收敛阈值,则停止迭代
            break

    return theta_0, theta_1, cost_history
# 这一code block用来调用上面的函数

# K值的选择需要我们不断尝试与比较,来获取更好的效果
possible_K_values = [3, 4, 5, 6, 7, 10]  # 可能得K值需要自己设定,对于不同的数据集,可能需要不同的K值
best_K = possible_K_values[0]
lowest_cost = float('inf')
theta_0_adaptive = 0
theta_1_adaptive = 0
cost_history_adaptive = []

for K in possible_K_values:  # 对于每一个K值
    theta_0_temp, theta_1_temp, cost_history_temp = adagrad_mini_batch_gradient_descent(x_values, y_values, K)
    if cost_history_temp[-1] < lowest_cost:
        lowest_cost = cost_history_temp[-1]
        best_K = K
        theta_0_adaptive = theta_0_temp
        theta_1_adaptive = theta_1_temp
        cost_history_adaptive = cost_history_temp

best_K, theta_0_adaptive, theta_1_adaptive, cost_history_adaptive[-1]
# 这一code block用来画出数据点和拟合直线
plot_data_and_line(x_values, y_values, theta_0_adaptive, theta_1_adaptive, cost_history_adaptive,
                   'Linear Regression using adagrad mini batch gradient descent, K= ' + str(best_K))

在这里插入图片描述

4. 多变量线性回归 Multivariate Linear Regression(在特征方面进行了改进,拓展到多个特征)

f θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 + ⋯ + θ n x n f_\theta(x)=\theta_0+\theta_1x_1+\theta_2x_2+\cdots+\theta_nx_n fθ(x)=θ0+θ1x1+θ2x2++θnxn

J ( θ 0 , θ 1 , . . . θ n ) = 1 2 N ∑ i = 1 N ( f θ ( x ( i ) ) − y ( i ) ) 2 J(\theta_0,\theta_1,...\theta_n)=\frac1{2N}\sum_{i=1}^N(f_\theta(x^{(i)})-y^{(i)})^2 J(θ0,θ1,...θn)=2N1i=1N(fθ(x(i))y(i))2

def multivariate_gradient_descent(X, y, batch_size=5, alpha=3, convergence_threshold=1e-8, max_iterations=10000):
    """
    Perform mini batch gradient descent with adaptive learning rate for multivariate linear regression.
    
    :param X:  这是一个矩阵,包含了所有的x值
    :param y:  这是一个list,包含了所有的y值
    :param batch_size:  这是一个int,表示batch的大小
    :param alpha:  这是一个float,表示学习率
    :param convergence_threshold:  这是一个float,表示收敛阈值
    :param max_iterations:  这是一个int,表示最大迭代次数
    :return:  这是一个tuple,包含了theta, cost_history,分别表示最终的theta和损失函数的变化,theta是一个list
    """
    m, n = X.shape  # m是样本数量,n是特征数量
    theta = np.zeros(n + 1)  # n+1 thetas 包含 theta_0
    X = np.hstack((np.ones((m, 1)), X))  # 在X前面加一列1,用来计算theta_0
    cost_history = []
    sum_squared_gradients = np.zeros(n + 1) + 0.0001  # 较小的值以避免被零除

    for _ in range(max_iterations):
        # 对数据进行随机打乱
        indices = np.arange(m)  # 生成一个0到m-1的list
        np.random.shuffle(indices)  # 对list进行随机打乱
        X = X[indices]  # 用打乱后的list对X进行重新排序
        y = y[indices]  # 用打乱后的list对y进行重新排序

        # Mini-batch updates
        for i in range(0, m, batch_size):  # i从0开始,每次增加batch_size
            X_batch = X[i:i + batch_size]  # 从i开始,取batch_size个元素
            y_batch = y[i:i + batch_size]  # 从i开始,取batch_size个元素

            # 梯度计算公式为: theta_j = theta_j - alpha / (sum_squared_gradients_j ** 0.5) * 1/N * sum((f_theta(x_i) - y_i) * x_i) 
            gradient = (1 / batch_size) * X_batch.T.dot(X_batch.dot(theta) - y_batch)  # 计算梯度
            sum_squared_gradients += gradient ** 2  # 更新sum_squared_gradients
            adaptive_alpha = alpha / np.sqrt(sum_squared_gradients)  # 计算学习率
            theta -= adaptive_alpha * gradient  # 更新theta

        cost = (1 / (2 * m)) * np.sum((X.dot(theta) - y) ** 2)  # 计算损失函数的值
        cost_history.append(cost)

        if len(cost_history) > 1 and abs(cost_history[-1] - cost_history[-2]) < convergence_threshold:
            # 如果损失函数的变化小于收敛阈值,则停止迭代
            break

    return theta, cost_history
# 这一code block用来调用上面的函数
# 请注意,这里的数据集是多变量线性回归的数据集
X_matrix = data[['x']].values
y_vector = data['y'].values
# best_K 已经在上面的代码中被赋值
theta_multivariate, cost_history_multivariate = multivariate_gradient_descent(X_matrix, y_vector, best_K)

theta_multivariate, cost_history_multivariate[-1]

5. L1正则化 L1 Regularization(在正则化方面进行了改进)

线性回归——lasso回归和岭回归(ridge regression) - wuliytTaotao - 博客园 (cnblogs.com)

def lasso_gradient_descent(X, y, batch_size=5, lambda_=0.1, alpha=3, convergence_threshold=1e-8, max_iterations=10000):
    """Perform mini batch gradient descent with adaptive learning rate and L1 regularization for multivariate linear regression."""
    m, n = X.shape  # m是样本数量,n是特征数量
    theta = np.zeros(n + 1)  # n+1 thetas 包含 theta_0
    X = np.hstack((np.ones((m, 1)), X))  # 在X前面加一列1,用来计算theta_0
    cost_history = []
    sum_squared_gradients = np.zeros(n + 1) + 0.0001  # 较小的值以避免被零除

    for _ in range(max_iterations):
        # 对数据进行随机打乱
        indices = np.arange(m)  # 生成一个0到m-1的list
        np.random.shuffle(indices)  # 对list进行随机打乱
        X = X[indices]  # 用打乱后的list对X进行重新排序
        y = y[indices]  # 用打乱后的list对y进行重新排序

        # Mini-batch updates
        for i in range(0, m, batch_size):  # i从0开始,每次增加batch_size
            X_batch = X[i:i + batch_size]  # 从i开始,取batch_size个元素
            y_batch = y[i:i + batch_size]  # 从i开始,取batch_size个元素

            # Compute gradient (including L1 penalty for j > 0)
            gradient = (1 / batch_size) * X_batch.T.dot(X_batch.dot(theta) - y_batch)  # 计算梯度
            gradient[1:] += lambda_ * np.sign(theta[1:])  # 对除theta_0外的所有theta添加L1正则化

            sum_squared_gradients += gradient ** 2  # 更新sum_squared_gradients
            adaptive_alpha = alpha / np.sqrt(sum_squared_gradients)  # 计算学习率
            theta -= adaptive_alpha * gradient  # 更新theta

        # Compute cost (including L1 penalty for j > 0)
        cost = (1 / (2 * m)) * np.sum((X.dot(theta) - y) ** 2) + lambda_ * np.sum(np.abs(theta[1:]))
        cost_history.append(cost)

        if len(cost_history) > 1 and abs(cost_history[-1] - cost_history[-2]) < convergence_threshold:
            # 如果损失函数的变化小于收敛阈值,则停止迭代
            break

    return theta, cost_history

如何选择lambda?

def determine_best_lambda(X, y, lambdas, num_folds=5, **kwargs):
    """Determine the best lambda using K-fold cross validation."""
    from sklearn.model_selection import KFold  # 此处使用sklearn中的KFold函数,用来进行交叉验证,与线性回归无关
    kf = KFold(n_splits=num_folds, shuffle=True, random_state=42)  # 生成交叉验证的数据,42是随机种子
    average_errors = []  # 用来保存每一个lambda的平均误差

    for lambda_ in lambdas:  # 对于每一个lambda
        fold_errors = []  # 用来保存每一折的误差

        for train_index, val_index in kf.split(X):
            X_train, X_val = X[train_index], X[val_index]  # 生成训练集和验证集
            y_train, y_val = y[train_index], y[val_index]  # 生成训练集和验证集

            theta, _ = lasso_gradient_descent(X_train, y_train, lambda_=lambda_, **kwargs)  # 训练模型

            # Compute validation error
            y_pred = np.hstack((np.ones((X_val.shape[0], 1)), X_val)).dot(theta)  # 计算预测值
            error = (1 / (2 * X_val.shape[0])) * np.sum((y_pred - y_val) ** 2)  # 计算误差
            fold_errors.append(error)

        average_errors.append(np.mean(fold_errors))

    best_lambda = lambdas[np.argmin(average_errors)]  # 选择平均误差最小的lambda
    return best_lambda, average_errors
# Lambda values to test
lambdas = [0, 0.001, 0.01, 0.1, 1, 10]

best_lambda, average_errors = determine_best_lambda(X_matrix, y_vector, lambdas)
best_lambda, average_errors
# Apply the multivariate gradient descent (using the single feature we have for this dataset)
X_matrix = data[['x']].values
y_vector = data['y'].values
theta_lasso, cost_history_lasso = lasso_gradient_descent(X_matrix, y_vector, best_K, best_lambda)

theta_lasso, cost_history_lasso[-1]
 # 选择平均误差最小的lambda
    return best_lambda, average_errors

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/253605.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么同源策略?

同源 同源指的是URL有相同的协议、主机名和端口号。 同源策略 同源策略指的是浏览器提供的安全功能&#xff0c;非同源的RUL之间不能进行资源交互 跨域 两个非同源之间要进行资源交互就是跨域。 浏览器对跨域请求的拦截 浏览器是允许跨域请求的&#xff0c;但是请求返回…

spring-kakfa依赖管理之org/springframework/kafka/listener/CommonErrorHandler错误

问题&#xff1a; 整个项目使用spring-boot2.6.8版本&#xff0c;使用gradle构建&#xff0c;在common模块指定了implementation org.springframework.kafka:spring-kafka:2.6.8’这个工程也都能运行&#xff08;这正常发送kafka消息和接收消息&#xff09;&#xff0c;但是执行…

nodejs+vue+微信小程序+python+PHP邮件过滤系统的设计与实现-计算机毕业设计推荐

邮件过滤系统根据权限类型进行分类&#xff0c;主要可分为用户和管理员二大模块。 管理员模块主要根据管理员对整个系统的管理进行设计&#xff0c;提高了管理的效率和规范[11]。邮件过滤系统综合网络空间开发设计要求。该系统主要设计并完成了管理过程中的用户登录、个人信息修…

持续集成交付CICD:基于 GitLabCI 与 JenkinsCD 实现后端项目发布

目录 一、实验 1. GitLabCI环境设置 2.优化GitLabCI共享库代码 3.JenkinsCD 发布后端项目 4.再次优化GitLabCI共享库代码 5.JenkinsCD 再次发布后端项目 一、实验 1. GitLabCI环境设置 &#xff08;1&#xff09;GitLab给后端项目添加CI配置路径 &#xff08;2&#xf…

万兆网络之屏蔽线序接法(下)

我们直接干吧 1.剥去网线外被&#xff0c;这个相信大家都会的&#xff0c;剪掉尼龙线 剥去的长度用水晶头和护套量度&#xff0c;多留一点长度用于撸直 为了插进去很紧&#xff0c;我用的是超五类的护套&#xff0c;只能顶到条纹底端就很费劲了 然后十字骨架留一小段&#xf…

【JAVA-Day69】抛出异常的精髓:深度解析 throw、throws 关键字,优雅处理异常问题

抛出异常的精髓&#xff1a;深度解析 throw、throws 关键字&#xff0c;优雅处理异常问题 &#x1f680; 抛出异常的精髓&#xff1a;深度解析 throw、throws 关键字&#xff0c;优雅处理异常问题 &#x1f680;一、什么是抛出异常 &#x1f60a;二、如何抛出异常 &#x1f914…

IDEA中,如何将maven项目变为SpringBoot项目?

第一步&#xff1a;新建Maven工程 这很简单不做过多赘述。 第二步&#xff1a;修改pom.xml文件 分别加入springboot父依赖&#xff0c;web依赖&#xff0c;test测试依赖&#xff0c;maven打包依赖。 <?xml version"1.0" encoding"UTF-8"?> <…

Android Stuido报错处理

仅用作报错记录。防止以后出项问题不知如何解决。 报错1 Dependency‘androidx.annotation:xx requires libraries and applications … 需要修改CompileSDKVersion更改为报错中提示的版本 打开项目build.gradle文件&#xff0c;将compileSdk和targetSdk修改为报错中提示的版…

Word写大论文常见问题(持续更新)

脚注横线未定格 解决方案&#xff1a;“视图”-“草图”&#xff0c;“引用”-“显示备注”-选择“脚注分隔符”&#xff0c;把横线前的空格删掉。 2.PPT做的图插入word中清晰度太低 解决方案&#xff1a;PPT-图形-“另存为图片”-“可缩放矢量图格式”-粘贴到word中。

FPGA简易加减法计算器设计

题目要求&#xff1a; &#xff08;1&#xff09;设计10以内的加减法计算器。 &#xff08;2&#xff09;1个按键用于指定加法或减法&#xff0c;一个用于指定加数或被加数&#xff0c;还有两个分别控制加数或被加数的增加或减少。 &#xff08;3&#xff09;设置的结果和计算的…

饥荒Mod 开发(十四):制作屏幕弹窗

饥荒Mod 开发(十三)&#xff1a;木牌传送 在上一个文章里面制作了一个传送选择页面&#xff0c;是一个全屏的窗口&#xff0c;那饥荒中如何制作一个全屏的窗口&#xff0c;下面介绍一下如何从零开始制作一个全屏窗口 制作屏幕窗口 饥荒中的全屏窗口都有一个基类 “Screen”,我…

JVM基础入门

JVM 基础入门 JVM 基础 聊一聊 Java 从编码到执行到底是一个怎么样的过程&#xff1f; 假设我们有一个文件 x.Java&#xff0c;你执行 javac&#xff0c;它就会变成 x.class。 这个 class 怎么执行的&#xff1f; 当我们调用 Java 命令的时候&#xff0c;class 会被 load 到…

Kafka相关知识

一、kafka架构 Kafka基础知识 Kafka是最初由Linkedin公司开发&#xff0c;是一个分布式、分区的、多副本的、多生产者、多订阅者&#xff0c;基于zookeeper协 调的分布式日志系统(也可以当做MQ系统)&#xff0c;常见可以用于webynginx日志、访问日志&#xff0c;消息服务等等&…

pycharm依赖管理(不要用pip freeze)

在使用python虚拟环境时&#xff0c;可以使用requirements.txt来管理当前项目的依赖。 注意&#xff0c;不要用 pip freeze > requirements.txt 这个命令&#xff0c;因为它会引入很多无关的包。 可以使用 pipreqs ./ --encodingutf-8 ./ 表示当前项目的目录&#xff0…

QT for Android安卓编译环境搭建+首次编译3个大坑

1、安装 编译环境能否搭建成功&#xff0c;主要是看各个依赖软件的版本是否匹配。依赖的软件有3个&#xff1a;JDK、安卓SDK、安卓NDK。 我的qt版本是5.14.1&#xff0c;我亲测以下版本可以成功让编译安卓&#xff1a; QT5.14 JDK1.8.0 安卓SDK26.1 安卓NDK20.1 在QT-&g…

为什么在Android中需要Context?

介绍 在Android开发中&#xff0c;Context是一个非常重要的概念&#xff0c;但是很多开发者可能并不清楚它的真正含义以及为什么需要使用它。本文将详细介绍Context的概念&#xff0c;并解释为什么在Android应用中需要使用它。 Context的来源 Context的概念来源于Android框架…

【算法Hot100系列】三数之和

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

第十三章总结

一.泛型 1.定义泛型类 泛型机制语法&#xff1a; 类名<T> 其中&#xff0c;T是泛型的名称&#xff0c;代表某一种类型。 【例13.6】创建带泛型的图书类 代码&#xff1a; 结果&#xff1a; 2.泛型的常规用法 (1)定义泛型类时声明多个变量 class MyClass<T1,T2…

python提取图片型pdf中的文字(提取pdf扫描件文字)

前言 文字型pdf提取&#xff0c;python的库一大堆&#xff0c;但是图片型pdf和pdf扫描件提取&#xff0c;还是有些难度的&#xff0c;我们需要用到OCR&#xff08;光学字符识别&#xff09;功能。 一、准备 1、安装OCR&#xff08;光学字符识别&#xff09;支持库 首先要安…

【PostgreSQL】从零开始:(十三)PostgreSQL-SQL语句操作架构(模式) Schema

Schema概述 PostgreSQL 数据库集群包含一个或多个命名数据库。角色和一些其他对象类型在整个集群中共享。与服务器的客户端连接只能访问单个数据库中的数据&#xff0c;该数据库在连接请求中指定。 用户不一定有权访问集群中的每个数据库。共享角色名称意味着不能在同一集群中…