机器学习—线性回归算法(Linear Regression)

一、基本概念

    线性回归是一种用于预测分析的统计学方法,它通过建立一个或多个自变量(解释变量)与一个因变量(响应变量)之间的线性关系来预测连续的数值。线性回归的目的是找到最佳拟合直线(在二维空间中)或超平面(在多维空间中),这条直线或超平面能够使预测值与实际观测值之间的差异最小化

    

二、线性回归简单分类与模型

    
分类:

  • 简单线性回归:只涉及一个自变量和一个因变量。
  • 多元线性回归:涉及两个或更多自变量。

    
线性回归模型:

  • 简单线性回归模型可以表示为: y = β 0 + β 1 x + ϵ y =\beta_0 + \beta_1 x + \epsilon y=β0+β1x+ϵ
    其中 y y y是因变量, x x x是自变量, β 0 \beta_0 β0是截距, β 1 \beta_1 β1是斜率, ϵ \epsilon ϵ是误差项。
        
  • 多元线性回归模型可以表示为: y = β 0 + β 1 x + β 2 x + ⋯ + β n x n + ϵ y = \beta_0 + \beta_1 x + \beta_2 x+ \dots+ \beta_nx_n+\epsilon y=β0+β1x+β2x++βnxn+ϵ
    其中, x 1 , x 2 , … , x n x_1,x_2,\dots,x_n x1,x2,,xn是自变量, β 1 , β 2 , … , β n \beta_1,\beta_2,\dots,\beta_n β1,β2,,βn是各自变量的系数。
        

三、线性回归的关键步骤

  1. 数据收集:收集包含自变量和因变量的数据集。
  2. 数据可视化:绘制散点图来观察数据点之间的关系。
  3. 模型假设:假设数据点之间存在线性关系。
  4. 参数估计:使用最小二乘法或其他优化技术来估计模型参数( β 1 , β 2 , … , β n \beta_1,\beta_2,\dots,\beta_n β1,β2,,βn)。
  5. 模型评估:使用均方误差(MSE)、R平方( R 2 R^2 R2)等指标来评估模型的拟合度。
  6. 模型诊断:检查模型的假设,如线性、独立性、同方差性和正态性。
  7. 预测:使用拟合好的模型来预测新的数据点。
        

四、线性回归问题分析

    线性回归是一种有监督学习方法。每个样本有 n n n个特征, x 1 , x 2 , … , x n x_1,x_2,\dots,x_n x1,x2,,xn

如下是广告投放与产品销量数据

TVRadiovideosales
250.538.570.522.5
214.72.622.618.9
151.839.57512.6

在这个例子中,每个样本有3个特征,分别是在TV、Radio、video的广告投放量。我们采集到每个样本的这 n n n 个特征的值及其结果:
x 1 ( i ) , x 2 ( i ) , … , x n ( i ) , y ( i ) x_1^{(i)},x_2^{(i)},\dots,x_n^{(i)},y^(i) x1(i),x2(i),,xn(i),y(i)
对于线性回归问题我们假定每个样本都有 N N N个特征 x 1 , x 2 , … , x N x_1,x_2,\dots,x_N x1,x2,,xN,我们采集到 M M M个样本的这 N N N个特征的值并标注其结果 y y y:
x 1 ( i ) , x 2 ( i ) , … , x N ( i ) , y ( i ) ( 1 ≤ i ≤ M ) x_1^{(i)},x_2^{(i)},\dots,x_N^{(i)},y^(i) \quad (1 \leq i \leq M) x1(i),x2(i),,xN(i),y(i)(1iM)

假定结果与这 N N N个特征之间都是线性关系:
y = h θ ( x ) = θ 0 + θ 1 x 1 + ⋯ + θ N x N = ∑ i = 0 N θ i x i y=h_\theta(x) = \theta_0 + \theta_1x_1+ \dots + \theta_Nx_N = \sum_{i=0}^{N} \theta_ix_i y=hθ(x)=θ0+θ1x1++θNxN=i=0Nθixi

写成矩阵的形式是:
h θ ( x ) = θ T X h_\theta(x) = \theta^TX hθ(x)=θTX

其中
θ = [ θ 0 θ 1 … θ N ] X = [ 1 x 1 … x N ] \theta= \left[ \begin{matrix} \theta_0 \\ \theta_1 \\ \dots \\ \theta_N \\ \end{matrix} \right] \quad X= \left[ \begin{matrix} 1 \\ x_1 \\ \dots \\ x_N \end{matrix} \right] θ= θ0θ1θN X= 1x1xN

对于每一个样本点,我们可以得出:
y ( i ) = θ T x ( i ) + ϵ ( i ) y^{(i)} = \theta^Tx^{(i)} + \epsilon^{(i)} y(i)=θTx(i)+ϵ(i)

假定误差 ϵ ( i ) ( 1 ≤ i ≤ M ) \epsilon^{(i)} (1 \leq i \leq M) ϵ(i)(1iM)是独立同分布的,服从均值为0,方差为某定值 σ 2 \sigma^2 σ2 的高斯分布(依据:中心极限定理)。
根据高斯分布的概率密度函数:
p ( ϵ ( i ) ) = 1 σ 2 π e x p ( − ( ϵ ( i ) ) 2 2 σ 2 ) p(\epsilon^{(i)})=\frac{1}{\sigma\sqrt{2\pi}}exp\left(-\frac{(\epsilon^{(i)})^2}{2\sigma^2}\right) p(ϵ(i))=σ2π 1exp(2σ2(ϵ(i))2)
得出:
p ( y ( i ) ∣ x ( i ) ; θ ) = 1 σ 2 π e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 σ 2 ) p(y^{(i)} | x^{(i)} ;\theta)=\frac{1}{\sigma\sqrt{2\pi}}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\sigma^2}\right) p(y(i)x(i);θ)=σ2π 1exp(2σ2(y(i)θTx(i))2)

此处, y ( i ) y^{(i)} y(i) 表示第 i i i 个样本的实际值, θ T x ( i ) \theta^Tx^{(i)} θTx(i) 表示第 i i i个样本的预测值。

    
θ \theta θ的似然函数

L ( θ ) = ∏ i = 1 m p ( y ( i ) ∣ x ( i ) ; θ ) = ∏ i = 1 m 1 σ 2 π e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 σ 2 ) \begin{aligned} L(\theta) &= \prod_{i=1}^{m} p(y^{(i)} | x^{(i)} ;\theta) \\ \\ &=\prod_{i=1}^{m} \frac{1}{\sigma\sqrt{2\pi}}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\sigma^2}\right) \\ \end{aligned} L(θ)=i=1mp(y(i)x(i);θ)=i=1mσ2π 1exp(2σ2(y(i)θTx(i))2)

为方便计算对它求似然函数的对数:

l ( θ ) = log ⁡ L ( θ ) = log ⁡ ∏ i = 1 m 1 σ 2 π e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 σ 2 ) = ∑ i = 1 m log ⁡ 1 σ 2 π e x p ( − ( y ( i ) − θ T x ( i ) ) 2 2 σ 2 ) = m ∗ log ⁡ 1 σ 2 π − 1 σ 2 ∗ 1 2 ∑ i = 1 m ( y ( i ) − θ T x ( i ) ) 2 \begin{aligned} l(\theta)& = \log L(\theta) \\ &=\log \prod_{i=1}^{m} \frac{1}{\sigma\sqrt{2\pi}}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\sigma^2}\right) \\ & = \sum_{i=1}^m \log \frac{1}{\sigma\sqrt{2\pi}}exp\left(-\frac{(y^{(i)}-\theta^Tx^{(i)})^2}{2\sigma^2}\right) \\ & = m \ast \log \frac{1}{\sigma\sqrt{2\pi}} - \frac{1}{\sigma^2} \ast \frac12 \sum_{i=1}^m(y^{(i)}-\theta^Tx^{(i)})^2 \end{aligned} l(θ)=logL(θ)=logi=1mσ2π 1exp(2σ2(y(i)θTx(i))2)=i=1mlogσ2π 1exp(2σ2(y(i)θTx(i))2)=mlogσ2π 1σ2121i=1m(y(i)θTx(i))2

J ( θ ) = 1 2 ∑ i = 1 m ( y ( i ) − θ T x ( i ) ) 2 = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 \begin{aligned} J(\theta) &= \frac12 \sum_{i=1}^m(y^{(i)}-\theta^Tx^{(i)})^2 \\ & = \frac12 \sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})^2 \end{aligned} J(θ)=21i=1m(y(i)θTx(i))2=21i=1m(hθ(x(i))y(i))2
极大似然估计是要求出 l ( θ ) l(\theta) l(θ) 的最大值,此处也就是求出 J ( θ ) J(\theta) J(θ)的最小值。

J ( θ ) J(\theta) J(θ)也是用优化方法求解线性回归问题的损失函数
    

五、线性回归问题的解法

1、最小二乘法

    
即求出上式中 J ( θ ) J(\theta) J(θ)的最小值。
我们将 M M M N N N维样本组成矩阵 X X X,

  • X X X的每一行对应一个样本,一共 M M M行。
  • X X X的每一列对应样本的一个维度,加上一个值恒为1的维度,一共 N + 1 N + 1 N+1列。
  • 这个额外的维度值恒为1,通常用于线性模型中的截距项,也就是说,每个样本都有一个额外的特征,其值为1。

具体形式如下:

特征1特征2特征N截距(1)
x11x12x1N1
x21x22x2N1
xM1xM2xMN1

代价函数 J ( θ ) = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J(\theta) = \frac12 \sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})^2 J(θ)=21i=1m(hθ(x(i))y(i))2 的最小值根据如上的描述其实就等价于 1 2 ( X θ − y ) T ( X θ − y ) \frac12 (X\theta -y)^T(X\theta - y) 21(y)T(y)
此处分析如下:

  1. 第一步:代价函数的定义是所有样本误差平方的平均值:
    J ( θ ) = 1 2 ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J(\theta) = \frac12 \sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})^2 J(θ)=21i=1m(hθ(x(i))y(i))2

  2. 向量化:在第二步中,我们将求和转换为向量形式。这里 h θ ( x ( i ) ) h_\theta(x^{(i)}) hθ(x(i))可以表示为 X θ X\theta ,其中

    • X X X是一个 M × ( N + 1 ) M \times (N+1) M×(N+1)的矩阵,包含了所有样本的输入特征,每一行对应一个样本,最后一列是1(对应于偏置项)。
    • θ \theta θ是一个 ( N + 1 ) × 1 (N + 1) \times 1 (N+1)×1的列向量,包含了模型参数,包括权重和偏置。
    • y y y是一个 M × 1 M \times 1 M×1的列向量,包含了所有样本的实际输出值。
  3. 误差向量:模型的预测误差可以表示为 X θ − y X\theta -y y,这是一个 M × 1 M \times 1 M×1的列向量。

  4. 误差的平方:误差向量的每个元素求平方仍然是一个 M × 1 M \times 1 M×1的列向量。

  5. 转置和点乘:将误差向量进行转置得到 ( X θ − y ) T (X\theta -y)^T (y)T,然后与原误差向量进行点乘
    ( X θ − y ) T ( X θ − y ) (X\theta -y)^T(X\theta - y) (y)T(y)。点乘是向量元素对应相乘后求和的操作,这会得到一个标量值。

  6. 最终表达式:由于点乘 ( X θ − y ) T ( X θ − y ) (X\theta -y)^T(X\theta - y) (y)T(y)得到的是一个标量,表示所有样本误差平方的总和,所以在代价函数前面乘以 1 2 \frac12 21 保持了原始代价函数的定义。

通过对代价函数 J ( θ ) J(\theta) J(θ)求偏导得出:
∂ l ( θ ) ∂ θ = 1 2 ( X θ − y ) T ( X θ − y ) = X T X θ − X T y \begin{aligned} \frac {\partial l(\theta)}{\partial \theta} & = \frac12(X\theta -y)^T(X\theta - y)\\ &=X^TX\theta - X^Ty \\ \end{aligned} θl(θ)=21(y)T(y)=XTXTy
令上式为0,可以得到
θ = ( X T X ) − 1 X T y \theta = (X^TX)^{-1} X^Ty θ=(XTX)1XTy

注意:此处 X T X X^TX XTX不一定是可逆的,为了解决这个问题,我们可以加上一个 λ \lambda λ扰动( λ \lambda λ是一个略大于0的实数):
θ = ( X T X + λ I ) − 1 X T y \theta = (X^TX + \lambda I)^{-1} X^Ty θ=(XTX+λI)1XTy
    

2、梯度下降法

    
    从上面我们可以得出损失函数 J ( θ ) J(\theta) J(θ)是一个凸函数,所以我们也可以用梯度下降算法来求得极值。

    梯度下降算法的目标是调整参数 θ \theta θ 以最小化损失函数 J ( θ ) J(\theta) J(θ)。梯度下降法通过计算损失函数相对于参数 θ \theta θ 的梯度,并更新参数以减少误差。梯度是一个向量,其元素是损失函数对每个参数的偏导数。线性回归的梯度可以表示为:
∇ θ J ( θ ) = 1 M X T ( X θ − y ) \nabla_\theta J(\theta) = \frac1M X^T(X\theta -y) θJ(θ)=M1XT(y)
这里:

  • ∇ θ J ( θ ) \nabla_\theta J(\theta) θJ(θ) 是损失函数 J ( θ ) J(\theta) J(θ) 对参数 θ \theta θ的梯度。
  • X T X^T XT是特征矩阵 X X X的转置。
  • X X X是特征矩阵,其维度是 M × ( N + 1 ) M \times (N+1) M×(N+1),其中 N N N是特征数量,加1是为了包含截距项。
  • θ \theta θ 是参数向量,维度是 ( N + 1 ) × 1 (N + 1) \times 1 (N+1)×1
  • M M M 是样本数量
  • y y y 是所有实际值构成的向量

梯度下降算法的更新规则如下:
θ : = θ − α ∇ θ J ( θ ) \theta := \theta - \alpha \nabla_\theta J(\theta) θ:=θαθJ(θ)

其中:

  • θ \theta θ 是当前参数向量
  • α \alpha α 是学习率,一个超参数,用于控制每次更新的步长

将梯度的表达式代入更新规则,我们得到线性回归的梯度下降更新公式:

θ : = θ − α × 1 M X T ( X θ − y ) \theta := \theta - \alpha \times \frac 1 M X^T(X\theta -y) θ:=θα×M1XT(y)

    在每次迭代中,我们都使用这个公式来更新参数 θ \theta θ 直到收敛到损失函数的最小值。这个过程通常重复进行,直到达到一定的迭代次数或梯度的变化非常小,表示参数更新不再显著,此时认为模型已经收敛。
    

六、线性回归中的过拟合与欠拟合

1、过拟合

    当一个模型在训练数据上表现得非常好,但是对于未见过的数据(即测试数据)泛化能力差,就发生了过拟合。这意味着模型过于复杂,学习了训练数据中的噪音和细节,而不仅仅是潜在的数据分布。
    
    
产生原因:

  • 模型可能过于复杂,拥有太多的参数或太高的灵活性。
  • 训练数据中可能包含噪音,模型学习了这些噪音而不是潜在的数据结构。
  • 模型训练时间过长,迭代次数过多。

    
解决方案:

应用正则化技术。

为了防止过拟合,我们在损失函数的后面加一项,称为正则化项,如下所示:
J ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( X ( i ) ) − y ( i ) ) 2 + λ Ω ( θ ) J(\theta) = \frac 1{2m} \sum_{i=1}^{m}(h_\theta(X^{(i)})-y^{(i)})^2 + \lambda \Omega(\theta) J(θ)=2m1i=1m(hθ(X(i))y(i))2+λΩ(θ)

常用的正则化技术有以下几种:

1、岭回归(Ridge Regression)

Ω ( θ ) = ∑ j = 1 n θ j 2 \Omega(\theta) = \sum_{j=1}^n \theta_j^2 Ω(θ)=j=1nθj2

以上被称为 L 2 L2 L2正则化,也称为欧几里得正则化或岭回归(Ridge Regression)。
    
应用场景:

  • 共线性问题:当数据特征之间存在高度相关性时,岭回归可以稳定模型参数的估计。
  • 参数估计稳定性:在参数数量接近或超过样本数量时,岭回归可以提供更稳定的参数估计。
  • 预测性能:当目标是构建一个在新数据上具有良好预测性能的模型时,岭回归通过减少模型复杂度来提高泛化能力。

    

2、套索回归 (Lasso回归)(Lasso Regression)

Ω ( θ ) = ∑ j = 1 n ∣ θ j ∣ \Omega(\theta) = \sum_{j=1}^n |\theta_j| Ω(θ)=j=1nθj

以上被称为 L 1 L1 L1 正则化,Lasso回归(Least Absolute Shrinkage and Selection Operator Regression)。Lasso回归通过惩罚绝对值较大的系数来实现特征选择,即它倾向于将一些系数压缩至零,从而实现稀疏模型。

    
应用场景:

  • 特征选择:套索回归通过将不重要的特征系数压缩至零来进行特征选择,适用于希望模型具有更少特征的情况。
  • 稀疏模型:当需要一个稀疏模型来提高解释性或进行更深入的特征影响分析时。
  • 变量数量很大:在高维数据集上,套索回归可以有效地减少特征空间。

以上两种正则化解决过拟合的思路:在求解参数 θ \theta θ,即( θ 0 , θ 1 , … , θ n \theta_0,\theta_1,\dots,\theta_n θ0,θ1,,θn)时,应保证其中的每一个参数的值都不能太大,如果太大,将会给与“惩罚”,即损失函数的值会增加。
    

3、弹性网(Elastic Net)

J ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( X ( i ) ) − y ( i ) ) 2 + λ 1 ∑ j = 1 n θ j 2 + λ 2 ∑ j = 1 n ∣ θ j ∣ J(\theta) = \frac 1{2m} \sum_{i=1}^{m}(h_\theta(X^{(i)})-y^{(i)})^2 + \lambda_1 \sum_{j=1}^n \theta_j^2 + \lambda_2 \sum_{j=1}^n |\theta_j| J(θ)=2m1i=1m(hθ(X(i))y(i))2+λ1j=1nθj2+λ2j=1nθj

弹性网(Elastic Net)回归是一种正则化线性模型,结合了L1正则化(Lasso回归)和L2正则化(岭回归)的特点。它旨在通过两种正则化项的组合来提供特征选择和防止过拟合的能力,同时保持模型的灵活性。
    

应用场景:

  • 特征选择与稳定性:弹性网结合了Lasso和Ridge的特点,可以在进行特征选择的同时,提供比Lasso更稳定的参数估计。
  • 多重共线性和特征数量多:当数据中存在多重共线性,并且特征数量较多时,弹性网可以平衡模型的复杂度和泛化能力。
  • 调整特征选择强度:通过调整L1和L2正则化项的比例,弹性网可以在特征选择的严格性和模型稳定性之间进行权衡。
        

三种正则化技术应用场景总结:

  1. 岭回归:适用于需要模型稳定性和预测性能的场景,尤其是在特征存在共线性时。
  2. 套索回归:适用于需要进行特征选择以简化模型的场景,特别是当变量数量很大时。
  3. 弹性网:适用于需要平衡特征选择和模型稳定性的场景,提供了Lasso和Ridge之间的灵活性。
        

2、欠拟合

    
    当一个模型不能充分捕捉到数据的内在结构和趋势时,就发生了欠拟合。这意味着模型太简单,没有足够的参数或复杂度来捕捉数据的关键特征。模型在训练集和测试集上的准确率都不高
    
产生原因:

  • 模型可能过于简单,例如线性模型可能无法捕捉到数据的非线性关系。
  • 特征选择不当,重要的特征被排除在模型之外。
  • 训练数据不足,模型没有足够的信息来学习数据的模式。
        

解决方案:
    
    欠拟合时需要继续提高模型在训练集上的准确率。
    

七、线性回归中的超参数与模型评估方法

1、超参数(Hyperparameter)

    超参数是机器学习模型中的参数,这些参数不是通过模型学习得到的,而是在模型训练之前设置的。它们通常用于控制学习过程中的某些方面,如模型的复杂度、学习能力和正则化强度。选择合适的超参数对于模型的性能至关重要,因为它们可以显著影响模型的泛化能力和预测准确性。

    本文中如上文岭回归、套索回归、弹性网中涉及到的参数 α \alpha α λ \lambda λ 在机器学习中被成为超参数(Hyperparameter)。

2、模型评估方法

1、Holdout 交叉验证

Holdout交叉验证是结合了Holdout验证和交叉验证元素的一种方法。
    
验证步骤:

  1. 将数据集分成训练集(如70%)、验证集(15%)、测试集(15%)
  2. 用暴力方式将所有可能的超参数在训练集上做训练,得到多个模型
  3. 将得到的模型在验证集上做评估,找出性能最佳的模型。这样就找到了我们所需要的超参数
  4. 用得到的超参数在训练集 + 验证集上做训练,得到一个新模型
  5. 用这个新模型在测试集上做测试,得到该模型的性能评估数据
  6. 用已经确定的超参数在100%的数据集上重新做训练,得到最终的模型

优点:

  • 简单性:方法相对简单,易于理解和实现。

缺点:

  • 方差问题:由于只使用了一个外部的保留集进行评估,结果可能具有较高的方差。

    
适用场景:

  • 当需要快速进行超参数调优和模型评估时。
  • 适用于样本数量较多的情况。

    

2、K折交叉验证(K-fold cross-validation)

一般常用10折交叉验证。
    
验证步骤:

  1. 将数据集随机分为K个等大小(或几乎等大小)的子集
  2. 每次迭代中,选择其中一个子集作为验证集,其余K-1个子集合并作为训练集。
  3. 模型在K-1个训练子集上训练,并在剩下的验证子集上评估。
  4. 重复K次,每次选择不同的子集作为验证集。
  5. 平均k次的结果或者使用其他结合的方式,最终得到待测超参数集的性能指标。

优点:

  • 评估稳定性:通过在K个子集上重复训练和测试,减少了评估结果的方差。
  • 更准确的性能估计:提供了比Holdout验证更可靠的模型性能估计。
  • 数据充分利用:所有数据点都被用于训练和测试。

缺点:

  • 计算成本:需要训练K次模型,计算成本较高。
  • K值选择:K值的选择可能影响评估结果。

    
适用场景:

  • 当需要更可靠的模型性能估计时。
  • 数据集不是特别大,且可以承受多次模型训练时。

    

3、留一交叉验证(Leave-One-Out Cross-Validation, LOOCV)

    
验证步骤:

  1. 每次迭代只留下一个样本作为验证集,其余所有样本作为训练集。
  2. 持续该过程直至每一个样本都作为验证样本。

优点:

  • 最充分的数据利用:每个样本都作为测试数据,确保了数据的充分利用。
  • 评估准确性:由于几乎所有数据都用于训练,模型评估非常接近实际使用情况。

缺点:

  • 计算成本极高:对于N个样本的数据集,需要训练N次模型,对于大型数据集不现实。
  • 方差问题:由于方差较小,可能会高估模型性能。

    
适用场景:

  • 数据集较小,且需要非常准确的模型评估时。
  • 当模型训练成本不是主要考虑因素时。

    
    
总述:

  • Holdout交叉验证:适用于数据集较大或模型训练成本较高的情况,需要快速简单的评估。
  • K折交叉验证:适用于需要更准确评估、数据集不是特别大、且可以承受较高计算成本的场景。
  • 留一交叉验证:适用于数据集较小、对评估准确性要求极高的场景,可以忽略计算成本。

在选择评估方法时,需要根据数据集的大小、模型的复杂度、训练成本和评估准确性的需求来综合考虑。

  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值