机器学习解决多元线性回归问题实例

题目:现有一张数据表格,要求通过年龄、性别、区域、婚否、小孩等预测收入。

依赖库:

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

step1:处理数据

将表中数据读取出来并存进数据结构里面

def data_preprocessing(path):
    data = pd.read_csv(path, encoding='gbk')
    y = data['收入'] / 1000
    x1 = data['年龄']
    x2 = data.apply(lambda x: 2 if x['性别'] == '男' else 1, axis=1)
    area = {'大城市': 4, '县城': 3, '乡镇': 2, '农村': 1}
    x3 = data.apply(lambda x: area[x['区域']] if x['区域'] in area else 0, axis=1)
    x4 = data.apply(lambda x: 2 if x['婚否'] == '是' else 1, axis=1)
    x5 = data['小孩']
    # 追加1列初始值为1做为矩阵运算的偏置项
    data['偏置项'] = 1
    res = np.column_stack([y, data['偏置项'], x1, x2, x3, x4, x5])
    return res

step2:构造损失函数(均方差)

这里本来应该构造模型函数f(x),再构建损失函数Loss(w)的,但多元线性函数较为简单就直接构建损失函数了。

def loss(w, data):
    """
    计算损失函数值
    :param w: 参数w
    :param data: 数据集
    :return: 损失函数值
    """
    y = data[..., 0: 1]
    x = data[..., 1:]
    return np.mean(np.square(np.matmul(x, w) - y)) / 2

step3:对损失函数求导,得到偏导函数(梯度函数)

以一个一元线性方程为例求偏导数为例

进而得出多元偏导也是一样的:

def loss_dw(w, data):
    """
    计算损失函数对w的偏导数
    :param w: 参数w
    :param data: 数据集
    :return: 损失函数对w的偏导数
    """
    y = data[..., 0: 1]
    x = data[..., 1:]
    return np.matmul(np.transpose(x), np.matmul(x, w) - y)

step4:梯度下降算法训练优化参数w

这里以Adam为例:

def get_batches(data, batch_size=40):
    """
    按batch_size划分小批量数据
    :param data: 全部样本
    :param batch_size: 划分大小
    :return: 分好的样本数据
    """
    for i in range(0, data.shape[0], batch_size):
        yield data[i:i + batch_size]


def Adam(w, data, batch_size, epochs = 100, alpha=1e-6, beta=1e-10, epsilon=1e-10, beta1=0.9, beta2=0.999, learning_rate=0.001):
    """
    使用Adam算法优化参数w
    :param w: 初始参数
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param epsilon: 防止除零的小常数
    :param beta1: 一级动量因子
    :param beta2: 二级动量因子
    :param learning_rate: 学习率
    :return: 优化后的参数w,步数列表和损失列表
    """
    k = 0
    m = 0
    v = 0
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        np.random.shuffle(data)
        for batch in get_batches(data, batch_size):
            k += 1
            gradient = loss_dw(w, batch)  # 计算梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_ab = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_ab)
            list_i.append(k)
            print(f'Step {k:02d}: \nw={w}\tloss={loss_ab:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代

            # 更新一阶动量
            m = beta1 * m + (1 - beta1) * gradient

            # 更新二阶动量
            v = beta2 * v + (1 - beta2) * np.square(gradient)

            # 偏差校正
            M = m / (1 - beta1 ** k)
            V = v / (1 - beta2 ** k)

            # 更新参数
            w = w - learning_rate * M / (np.sqrt(V) + epsilon)

            if abs(loss(w, batch) - loss_ab) <= beta:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

step5:整理整个流程,在main函数调用

def draw(steps, losses):
    """
    绘制损失函数随步数变化的图
    :param steps: 步数
    :param losses: 损失函数值
    """
    plt.plot(steps, losses)
    plt.xlabel('Step')
    plt.ylabel('Loss')
    plt.title('Loss Wave')
    plt.show()


if __name__ == '__main__':
    # 获取样本数据
    data = data_preprocessing('多元线性回归数据.csv')
    # 初始化参数
    w = np.zeros([6, 1])
    batch_size = 600
    # 使用Adam算法进行优化
    w_opt, steps, losses = Adam(w, data, batch_size, epochs=10000)
    # 打印优化后的参数
    print(f'Optimized parameters: \nw = {w_opt} loss = {loss(w, data)}')
    # 绘制损失函数随步数变化的图
    draw(steps, losses)

得出训练结果:

注:附上其他六种梯度下降算法源码

SGD:

def SGD(w, data, batch_size=-1, learning_rate=0.00000001, epochs=1000, alpha=1e-8,
        beta=1e-8, loss=loss, loss_dw=loss_dw):
    """
    使用随机梯度下降算法优化参数w
    :param w: 初始参数w
    :param learning_rate: 学习率
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param loss: 损失函数
    :param loss_dw: 损失函数对w的偏导数
    :return: 优化后的参数a和b,步数列表和损失列表
    """
    k = 0
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        for batch in get_batches(data, batch_size):
            k += 1
            gradient = loss_dw(w, batch)  # 计算梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_ab = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_ab)
            list_i.append(k)
            print(f'Step {k:02d}: loss={loss_ab:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha and alpha != -1:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代
            # 更新参数
            w = w - learning_rate * gradient
            if abs(loss(w, batch) - loss_ab) <= beta and beta != -1:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

Momentum:

def Momentum(w, data, batch_size=-1, learning_rate=0.000000002, epochs=1000, alpha=1e-8,
             beta=1e-8, gamma=0.5, loss=loss, loss_dw=loss_dw):
    """
    使用动量随机梯度下降算法优化参数w
    :param w: 初始参数(w0, w1)
    :param learning_rate: 学习率
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param gamma: 动量因子
    :param loss: 损失函数
    :param loss_dw: 损失函数对w的偏导数
    :return: 优化后的参数w,步数列表和损失列表
    """
    k = 0
    v = 0
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        for batch in get_batches(data, batch_size):
            k += 1
            gradient = loss_dw(w, batch)  # 计算损失函数的梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_w = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_w)
            list_i.append(k)
            print(f'Step {k:02d}: \tloss={loss_w:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha and alpha != -1:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代
            # 更新动量
            v = v * gamma + learning_rate * gradient
            # 更新参数
            w = w - v
            if abs(loss(w, batch) - loss_w) <= beta and beta != -1:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

NAG:

def NAG(w, data, batch_size=-1, learning_rate=0.000000003, epochs=1000, alpha=1e-8,
        beta=1e-8, gamma=0.5, loss=loss, loss_dw=loss_dw):
    """
    使用Nesterov加速梯度下降算法优化参数w
    :param w: 初始参数(w0, w1)
    :param learning_rate: 学习率
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param gamma: 动量因子
    :param loss: 损失函数
    :param loss_dw: 损失函数对w的偏导数
    :return: 优化后的参数w,步数列表和损失列表
    """
    k = 0
    v = 0
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        for batch in get_batches(data, batch_size):
            k += 1
            w_pred = w - gamma * v  # 计算预测参数
            gradient = loss_dw(w_pred, batch)  # 计算预测参数损失函数的梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_w = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_w)
            list_i.append(k)
            print(f'Step {k:02d}: loss={loss_w:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha and alpha != -1:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代
            # 更新动量
            v = gamma * v + learning_rate * gradient
            # 更新参数
            w = w - v
            if abs(loss(w, batch) - loss_w) <= beta and beta != -1:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

Adagrad:

def Adagrad(w, data, batch_size=-1, learning_rate=0.03, epochs=1000, alpha=1e-8,
            beta=1e-8, epsilon=1e-6, loss=loss, loss_dw=loss_dw):
    """
    使用Adagrad算法优化参数w
    :param w: 初始参数(w0, w1)
    :param learning_rate: 学习率
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param epsilon: 防止除零的小常数
    :param loss: 损失函数
    :param loss_dw: 损失函数对w的偏导数
    :return: 优化后的参数w,步数列表和损失列表
    """
    k = 0
    E_g = 0  # 初始化累积梯度平方
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        np.random.shuffle(data)
        for batch in get_batches(data, batch_size):
            k += 1
            gradient = loss_dw(w, batch)  # 计算损失函数的梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_w = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_w)
            list_i.append(k)
            print(f'Step {k:02d}: \tloss={loss_w:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha and alpha != -1:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代
            # 更新累积梯度平方
            E_g = E_g + np.square(gradient)

            # 更新参数
            w = w - (learning_rate / np.sqrt(E_g + epsilon)) * gradient

            if abs(loss(w, batch) - loss_w) <= beta and beta != -1:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

RMSprop:

def RMSprop(w, data, batch_size=-1, learning_rate=0.001, epochs=1000, alpha=1e-8,
            beta=1e-8, epsilon=1e-6, gamma=0.9, loss=loss, loss_dw=loss_dw):
    """
    使用RMSprop算法优化参数w
    :param w: 初始参数(w0, w1)
    :param learning_rate: 学习率
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param epsilon: 防止除零的小常数
    :param gamma: 梯度平方的衰减率
    :param loss: 损失函数
    :param loss_dw: 损失函数对w的偏导数
    :return: 优化后的参数w,步数列表和损失列表
    """
    k = 0
    E_g = 0  # 初始化累积梯度平方
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        for batch in get_batches(data, batch_size):
            k += 1
            gradient = loss_dw(w, batch)  # 计算损失函数的梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_w = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_w)
            list_i.append(k)
            print(f'Step {k:02d}: \tloss={loss_w:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha and alpha != -1:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代
            # 更新累积梯度平方
            E_g = E_g * gamma + (1 - gamma) * np.square(gradient)

            # 更新参数
            w = w - (learning_rate / np.sqrt(E_g + epsilon)) * gradient

            if abs(loss(w, batch) - loss_w) <= beta and beta != -1:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

AdaDelta:

def AdaDelta(w, data, batch_size=-1, epochs=1000, alpha=1e-3, beta=1e-3,
             epsilon=1e-6, decay_rate=0.95, loss=loss, loss_dw=loss_dw):
    """
    使用AdaDelta算法优化参数w
    :param w: 初始参数(w0, w1)
    :param data: 样本数据
    :param alpha: 梯度阈值
    :param beta: 损失值变化阈值
    :param epsilon: 防止除零的小常数
    :param decay_rate: 梯度平方的衰减率
    :param loss: 损失函数
    :param loss_dw: 损失函数对w的偏导数
    :return: 优化后的参数w,步数列表和损失列表
    """
    k = 0
    E_g = 0  # 初始化累积梯度平方
    E_x = 0  # 初始化累积梯度平方
    list_loss, list_i = [], []  # 用于存储损失值和步数
    for _ in range(epochs):
        for batch in get_batches(data, batch_size):
            k += 1
            gradient = loss_dw(w, batch)  # 计算损失函数的梯度
            gradient_modlue = np.sqrt(np.sum((np.square(gradient))))  # 计算梯度的范数
            loss_w = loss(w, batch)  # 计算当前损失函数值
            list_loss.append(loss_w)
            list_i.append(k)
            print(f'Step {k:02d}: \tloss={loss_w:.18f}\tgrad={gradient_modlue:.18f}')
            if gradient_modlue <= alpha and alpha != -1:
                return w, list_i, list_loss  # 如果梯度的范数小于阈值,停止迭代
            # 累积梯度平方
            E_g = E_g * decay_rate + (1 - decay_rate) * np.square(gradient)

            # 计算w的RMS
            RMS_w = np.sqrt(E_g + epsilon)

            # 计算w的RMS更新量
            RMS_x = np.sqrt(E_x + epsilon)

            # 计算w的更新量x
            x = RMS_x / RMS_w * gradient

            # 更新w的更新量平方累积E_x
            E_x = E_x * decay_rate + (1 - decay_rate) * np.square(x)

            # 更新参数
            w = w - x

            if abs(loss(w, batch) - loss_w) <= beta and beta != -1:
                return w, list_i, list_loss  # 如果损失函数值的变化小于阈值,停止迭代
    return w, list_i, list_loss

<think>好的,用户想了解多元线性回归的原理及其在机器学习中的应用实例。我需要先回顾一下多元线性回归的基础知识,确保自己理解正确。首先,多元线性回归线性回归的扩展,用于处理多个自变量对因变量的影响。公式应该是这样的:$$y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \dots + \beta_n x_n + \epsilon$$,其中$\beta_0$是截距,其他$\beta$是系数,$\epsilon$是误差项。 接下来,用户可能想知道如何求解这些系数。通常使用最小二乘法,通过最小化残差平方和来找到最优解。这里可能需要解释一下损失函数,比如:$$L = \sum_{i=1}^{m}(y_i - \hat{y_i})^2$$,然后通过求导或者矩阵运算来得到参数的闭式解。矩阵形式的话,应该是$\beta = (X^T X)^{-1} X^T y$。不过要注意,如果特征之间存在多重共线性,$(X^T X)$可能不可逆,这时候可能需要用正则化方法,比如岭回归或者LASSO,这可能在引用[4]里有提到。 然后,应用实例部分需要找一个实际的案例。引用[4]中提到了近红外光谱分析的应用,可以详细说明一下。比如,用近红外光谱数据预测某种物质的含量,使用多元线性回归建模,并比较不同正则化方法的效果。同时,引用[2]和[3]可能提供了其他应用的例子,比如房价预测或者销售额预测,这些也是常见的例子。 用户还提到需要教程,可能需要给出Python代码示例。比如使用scikit-learn库中的LinearRegression,或者展示如何实现岭回归。代码要简洁,并且加上注释,帮助用户理解每一步的作用。例如加载数据、划分训练集和测试集、训练模型、评估指标如均方误差等。 另外,用户可能想知道多元线性回归机器学习中的定位,比如作为基线模型,这在引用[2]中提到了。需要解释为什么线性回归通常作为基准,以及它的优缺点,比如计算快、可解释性强,但无法处理非线性关系。 还有可能需要注意的问题,比如特征缩放是否必要,如何处理分类变量,多重共线性的影响,以及正则化的应用场景。这些都是在实际应用中需要注意的点,可以结合引用[3]和[4]中的内容进行说明。 最后,生成的相关问题需要围绕用户的需求展开,比如如何评估模型性能,处理过拟合的方法,与其他回归算法的比较等。确保问题具有针对性,能够引导用户进一步学习。 总结一下,回答的结构应该是先讲原理,包括模型方程、参数求解方法、评估指标,然后给出应用实例和代码示例,最后讨论注意事项和相关问题。需要确保引用正确的参考文献,比如引用[4]中的近红外光谱案例,引用[2]中的基线模型说明等。</think>### 多元线性回归原理及实例教程 #### 一、多元线性回归原理 1. **模型定义** 多元线性回归通过多个自变量(特征)预测因变量(目标),模型表达式为: $$y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \dots + \beta_n x_n + \epsilon$$ 其中: - $y$:因变量 - $\beta_0$:截距项 - $\beta_1, \dots, \beta_n$:特征系数 - $x_1, \dots, x_n$:自变量 - $\epsilon$:随机误差(服从正态分布) 2. **参数求解** 使用**最小二乘法**最小化残差平方和: $$L = \sum_{i=1}^{m}(y_i - \hat{y_i})^2$$ 闭式解(矩阵形式): $$\beta = (X^T X)^{-1} X^T y$$ 当$X^T X$不可逆时(如多重共线性),需引入正则化(如岭回归、LASSO)[^4]。 3. **评估指标** - **均方误差(MSE)**:$MSE = \frac{1}{m}\sum_{i=1}^{m}(y_i - \hat{y_i})^2$ - **决定系数($R^2$)**:衡量模型解释方差的比例。 --- #### 二、应用实例:近红外光谱分析 **目标**:通过近红外光谱数据预测物质含量(如蛋白质浓度)。 **步骤**: 1. **数据预处理** - 光谱数据标准化(消除量纲差异) - 划分训练集与测试集(比例7:3) 2. **建模与优化** - **普通多元线性回归**:直接拟合,可能过拟合。 - **岭回归**:添加$L_2$正则化项,解决多重共线性。 $$L_{\text{ridge}} = \sum_{i=1}^{m}(y_i - \hat{y_i})^2 + \lambda \sum_{j=1}^{n} \beta_j^2$$ - **LASSO**:添加$L_1$正则化,实现特征选择。 $$L_{\text{LASSO}} = \sum_{i=1}^{m}(y_i - \hat{y_i})^2 + \lambda \sum_{j=1}^{n} |\beta_j|$$ 3. **Python代码示例** ```python from sklearn.linear_model import LinearRegression, Ridge from sklearn.metrics import mean_squared_error, r2_score from sklearn.model_selection import train_test_split # 加载数据(假设X为光谱数据,y为浓度) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) # 普通多元线性回归 model_lr = LinearRegression() model_lr.fit(X_train, y_train) y_pred = model_lr.predict(X_test) print(f"MSE: {mean_squared_error(y_test, y_pred)}, R²: {r2_score(y_test, y_pred)}") # 岭回归(调节超参数λ) model_ridge = Ridge(alpha=0.5) model_ridge.fit(X_train, y_train) y_pred_ridge = model_ridge.predict(X_test) ``` --- #### 三、机器学习中的应用场景 1. **基线模型**:作为复杂模型(如神经网络)的基准[^2]。 2. **可解释性需求**:分析特征对目标的影响(如房价预测中房间数、位置的作用)[^3]。 3. **高维数据**:结合正则化处理特征冗余(如基因表达数据分析)[^4]。 --- #### 四、注意事项 1. **特征相关性检查**:使用热力图或方差膨胀因子(VIF)检测多重共线性。 2. **正则化选择**:岭回归适合特征较多且相关性高;LASSO适合稀疏特征场景。 3. **非线性扩展**:通过多项式特征或核方法提升模型灵活性[^1]。 --- §§ 相关问题 §§ 1. 如何评估多元线性回归模型的性能? 2. 多元线性回归中如何处理过拟合问题? 3. 多元线性回归与逻辑回归的区别是什么? 4. 如何用Python实现LASSO回归? 5. 近红外光谱分析中,正则化参数$\lambda$如何选择?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值