线性回归(梯度下降)2021-04-16

线性回归

基本思想

线性回归是我们高中学习的线性回归的思想延伸,所以本人感觉不是很难接受。
线性回归是通过若干个相关的离散的点来模拟出的能够预测(由自变量改变引起)因变量的线性图线的一种思想和方法。

1,线性回归

1.1线性回归概念

如果研究的线性代数只包含一个自变量和一个因变量,且二者的关系可以通过一条直线近似的刻画时,这种回归就称为一元线性回归。如果回归分析中涉及到两个及以上的自变量,且自变量与因变量是线性关系,就称为多元线性回归。
线性关系:两个变量之间存在一次方函数关系,通俗一点讲,就是如果如果把这两个变量分别作为点的横坐标与纵坐标,其图象是平面上的一条直线,则这两个变量之间的关系就是线性关系。
一元线性代数的公式: y = a ∗ x + b y=a*x+b y=ax+b
问题:如何才能更好的去模拟现有的线性关系呢?
接下来引入的就是能解决这个问题的方法:构造损失函数(比较洋气一点的名字叫做loss 函数),首先loss函数是个怎样的概念,本人理解,loss函数就是一个把原先函数的预测值(记为 y ^ \hat{y} y^)当做新的自变量,把L当做因变量的函数,表达式表示为 L = 1 n ∑ i = 1 n ( y i ^ − y i ) 2 L=\frac{1}{n}\sum_{i=1}^{n}\quad(\hat{y_i}-y_i)^{2} L=n1i=1n(yi^yi)2公式表达了预测值与真实值之间的平均的平方距离,一般称其为MAE(mean square error)均方误差将上面y的函数表达式代入得到: L ( a , b ) = 1 n ∑ i = 1 n ( a x i + b − y i ) 2 L(a,b)=\frac{1}{n}\sum_{i=1}^{n}\quad(ax_i+b-y_i)^{2} L(a,b)=n1i=1n(axi+byi)2然后把a和b看成L的自变量,构造完函数就考虑求未知数的问题。

1.2 回归参数的求解方法

1.21 最小二乘法(least square method

不要感觉很陌生,其实我们高中不知道用了多少次,下面的例子中的公式就是由最小二乘法得到的呀,只不过我们很少有人问为什么罢了吧。
求出这样一些未知参数使得样本点和拟合线的总误差(距离)最小
直观感受一下:(图借鉴与知乎某作者)在这里插入图片描述
由于误差有正有负,会有相互抵消的情况存在,所以我们一般求其差的平方。

2.211 看看怎么来?

手工推导:在这里插入图片描述

1.22 梯度下降法(gradient descent,GD)

梯度下降不懂得话,请点击梯度下降
在这里的应用为: a − α δ L δ a → a a-\alpha\frac{\delta L}{\delta a}→a aαδaδLa
b − α δ L δ b → b b-\alpha\frac{\delta L}{\delta b}→b bαδbδLb

2,一元线性回归实例

为了帮助大家更快的接受这个知识点,我们不如把高中的线性回归例题拿来作为实例:在这里插入图片描述
在这里插入图片描述
我们只要解决第二问就行了,我会先归出手工推导一遍,稍后给出相应的代码实现。

2.1 手工推导

在这里插入图片描述

2.2 代码实现

提示: 代码中涉及的批量与随机的方法在上面的梯度下降的链接里有讲解。

print ("零件个数与与加工时间表")
print("序号:1     2    3    4")    
print("个数:2     3    4    5")  
print("时间:2.5   3    4    4.5\n")
import matplotlib.pyplot as plt
import matplotlib
from math import pow       #做平方用
import random      #它的引入是为了下面的批量梯度算法的实现
x = [2,3,4,5]
y = [2.5,3,4,4.5]
#线性回归函数为 y=b+a*x
#参数定义
b = 0.1       #对 b 赋值
a = 0.1       #对 a 赋值
alpha = 0.1   #学习率
m = len(x)
count0 = 0
b_list = []
a_list = []
#使用批量梯度下降法
for num in range(10000):
    count0 += 1
    diss = 0   #误差
    deriv0 = 0 #对 b 导数
    deriv1 = 0 #对 a 导数
    #求导
    for i in range(m):
        deriv0 += (b+a*x[i]-y[i])/m
        deriv1 += ((b+a*x[i]-y[i])/m)*x[i]
    #更新 b 和 a
    for i in range(m):
        b = b - alpha*((b+a*x[i]-y[i])/m) 
        a = a - alpha*((b+a*x[i]-y[i])/m)*x[i]
    #求损失函数 J (θ)
    for i in range(m):
        diss = diss + (1/(2*m))*pow((b+a*x[i]-y[i]),2)
    b_list.append(b)
    a_list.append(a)
    #如果误差已经很小,则退出循环
    if diss <= 0.001:
        break
#使用随机梯度下降法
b1 = 0.1        #对 b1 赋值
a1 = 0.1        #对 a1 赋值
count1 = 0
b1_list = []
a1_list = []
for num in range(10000):
    count1 += 1
    diss = 0     #误差
    deriv2 = 0   #对 b1 偏导
    deriv3 = 0   #对 a1 偏导
    #求导
    for i in range(m):
        deriv2 += (b1+a1*x[i]-y[i])/m
        deriv3 += ((b1+a1*x[i]-y[i])/m)*x[i]
    #更新 b 和 a
    for i in range(m):
        b1 = b1 - alpha*((b1+a1*x[i]-y[i])/m) 
        a1 = a1 - alpha*((b1+a1*x[i]-y[i])/m)*x[i]
    #求损失函数 L(a,b)
    rand_i = random.randrange(0,m)
    diss = diss + (1/(2*m))*pow((b1+a1*x[rand_i]-y[rand_i]),2)
    b1_list.append(b1)
    a1_list.append(a1)
    #如果误差已经很小,则退出循环
    if diss <= 0.001:
        break 
print("批量梯度下降最终得到b={},a={}".format(b,a))
print("           得到的回归函数是:y={}+{}*x".format(b,a))
print("随机梯度下降最终得到b={},a={}".format(b1,a1))
print("           得到的回归函数是:y={}+{}*x".format(b1,a1))
#画原始数据图和函数图
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
plt.plot(x,y,'bo',label='数据',color='black')
plt.plot(x,[b+a*x for x in x],label='批量梯度下降',color='red')
plt.plot(x,[b1+a1*x for x in x],label='随机梯度下降',color='blue')
plt.xlabel('x(零件个数)')
plt.ylabel('y(加工时间)')
plt.legend()
plt.show()
plt.scatter(range(count0),b_list,s=1)
plt.scatter(range(count0),a_list,s=1)
plt.xlabel('上方为b,下方为a')
plt.show()
plt.scatter(range(count1),b1_list,s=3)
plt.scatter(range(count1),a1_list,s=3)
plt.xlabel('上方为b,下方为a')
plt.show()

代码运行结果:
在这里插入图片描述
在这里插入图片描述
其余的两个图像感兴趣的同学可以给我留言,我会在第一时间回评。
以下观点大多借鉴,欢迎大佬指教。

3,多元线性回归及梯度下降*

3.1 定义数据

以下面一组数据为例子:在这里插入图片描述
以上角标作为行索引,以下角标作为列索引
第二行可以写成: x ( 2 ) = [ 916 1201 5 . . . 33 ] x^{(2)}=\begin{bmatrix} 916\\1201\\5\\...\\33 \end{bmatrix} x(2)=91612015...33
位于第二行第一列的数字写成:
x 1 ( 2 ) = 916 x^{(2)}_1=916 x1(2)=916
以下角标来区分位置,以便于后期运算。

3.2 定义函数

(1)设置一个回归方程:
h θ ( x ) = θ 0 + θ 1 x 1 + θ 2 x 2 + θ 3 x 3 + . . . + θ n x n h_\theta(x)=\theta_0+\theta_1 x_1+\theta_2x_2+\theta_3x_3+...+\theta_nx_n hθ(x)=θ0+θ1x1+θ2x2+θ3x3+...+θnxn
(2)添加一个列向量:
x 0 = [ 1 1 1 1... 1 ] T x_0=\begin{bmatrix} 1&1&1&1...&1\end{bmatrix}^T x0=[1111...1]T
这里的上角标T表示 x 0 x_0 x0矩阵的倒置,就是由行到列变为由列到行,使得其满足矩阵乘法的要求。
这样方程可以写为:
h θ ( x ) = θ 0 x 0 + θ 1 x 1 + θ 2 x 2 + θ 3 x 3 + . . . + θ n x n h_\theta(x)=\theta_0x_0+\theta_1 x_1+\theta_2x_2+\theta_3x_3+...+\theta_nx_n hθ(x)=θ0x0+θ1x1+θ2x2+θ3x3+...+θnxn
既不会影响到方程的结果,而且使x与 θ \theta θ的数量一致以便于矩阵计算。
为了方便表达,分别记为:
X = [ x 0 x 1 x 2 x 3 . . . x n ] , θ = [ θ 0 θ 1 θ 2 θ 3 . . . θ n ] X=\begin{bmatrix} x_0\\x_1\\x_2\\x_3\\...\\x_n \end{bmatrix},\theta=\begin{bmatrix} \theta_0\\\theta_1\\\theta_2\\\theta_3\\...\\\theta_n \end{bmatrix} X=x0x1x2x3...xn,θ=θ0θ1θ2θ3...θn
方程再次变形:
h θ ( x ) = [ θ 0 θ 1 θ 2 θ 3 . . . θ n ] T [ x 0 x 1 x 2 x 3 . . . x n ] h_\theta(x)=\begin{bmatrix} \theta_0&\theta_1&\theta_2&\theta_3&...&\theta_n \end{bmatrix}_T\begin{bmatrix} x_0\\x_1\\x_2\\x_3\\...\\x_n \end{bmatrix} hθ(x)=[θ0θ1θ2θ3...θn]Tx0x1x2x3...xn
(3)由回归方程推导出损失方程:在这里插入图片描述

3.3应用梯度下降

在这里插入图片描述
计算时要一个一个计算,以确保数据统一变化。在执行次数足够多的迭代后,就能取得达到要求的 θ j \theta_j θj的值。

3.4 著名的鸢尾花数据集

Iris 鸢尾花数据集内包含 3 类,分别为山鸢尾(Iris-setosa)、变色鸢尾(Iris-versicolor)和维吉尼亚鸢尾(Iris-virginica),共 150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这 4 个特征预测鸢尾花卉属于哪一品种。 这是本文章所使用的鸢尾花数据集: sl:花萼长度 ;sw:花萼宽度 ;pl:花瓣长度 ;pw:花瓣宽度; type:类别:(Iris-setosa、Iris-versicolor、Iris-virginica 三类)
在这里插入图片描述
数据的下载:

鸢尾花数据下载链接
在这里插入图片描述
代码实现:

def MGD_train(X, y, alpha=0.0001, maxIter=1000, theta_old=None):
    '''
    MGD训练线性回归
    传入:
        X       :  已知数据  
        y       :  标签
        alpha   :  学习率
        maxIter :  总迭代次数 
    返回:
        theta : 权重参数
    '''
    # 初始化权重参数
    theta = np.ones(shape=(X.shape[1],))
    if not theta_old is None:
        # 假装是断点续训练
        theta = theta_old.copy()
    
    #axis=1 表示横轴,方向从左到右;axis=0 表示纵轴,方向从上到下
    for i in range(maxIter):
        # 预测
        y_pred = np.sum(X * theta, axis=1)
        # 全部数据得到的梯度
        gradient = np.average((y - y_pred).reshape(-1, 1) * X, axis=0)
        # 更新学习率
        theta += alpha * gradient
    return theta


def SGD_train(X, y, alpha=0.0001, maxIter=1000, theta_old=None):
    '''
    SGD训练线性回归
    传入:
        X       :  已知数据  
        y       :  标签
        alpha   :  学习率
        maxIter :  总迭代次数
        
    返回:
        theta : 权重参数
    '''
    # 初始化权重参数
    theta = np.ones(shape=(X.shape[1],))
    if not theta_old is None:
        # 假装是断点续训练
        theta = theta_old.copy()
    # 数据数量
    data_length = X.shape[0]
    for i in range(maxIter):
        # 随机选择一个数据
        index = np.random.randint(0, data_length)
        # 预测
        y_pred = np.sum(X[index, :] * theta)
        # 一条数据得到的梯度
        gradient = (y[index] - y_pred) * X[index, :]
        # 更新学习率
        theta += alpha * gradient
    return theta
    
    
def MBGD_train(X, y, alpha=0.0001, maxIter=1000, batch_size=10, theta_old=None):
    '''
    MBGD训练线性回归
    传入:
        X          :  已知数据  
        y          :  标签
        alpha      :  学习率
        maxIter    :  总迭代次数
        batch_size :  没一轮喂入的数据数
        
    返回:
        theta : 权重参数
    '''
    # 初始化权重参数
    theta = np.ones(shape=(X.shape[1],))
    
    if not theta_old is None:
        # 假装是断点续训练
        theta = theta_old.copy()
    
    # 所有数据的集合
    all_data = np.concatenate([X, y.reshape(-1, 1)], axis=1)
    for i in range(maxIter):
        # 从全部数据里选 batch_size 个 item
        X_batch_size = np.array(random.choices(all_data, k=batch_size))
        
        # 重新给 X, y 赋值
        X_new = X_batch_size[:, :-1]
        y_new = X_batch_size[:, -1]
        
        # 将数据喂入,更新 theta
        theta = MGD_train(X_new, y_new, alpha=0.0001, maxIter=1, theta_old=theta)
    return theta


def GD_predict(X, theta):
    '''
    用于预测的函数
    传入:
        X     : 数据
        theta : 权重
    返回:
        y_pred: 预测向量
    '''
    y_pred = np.sum(theta * X, axis=1)
    # 实数域空间 -> 离散三值空间,则需要四舍五入
    y_pred = (y_pred + 0.5).astype(int)
    return y_pred 


def calc_accuracy(y, y_pred):
    '''
    计算准确率
    传入:
        y        : 标签
        y_pred   : 预测值
    返回:
        accuracy : 准确率
    '''
    return np.average(y == y_pred)*100
# 读取数据
iris_raw_data = pd.read_csv('iris.data', names  =['sepal length', 'sepal width', 'petal length', 'petal width', 'class'])
# 将三种类型映射成整数
Iris_dir = {'Iris-setosa': 1, 'Iris-versicolor': 2, 'Iris-virginica': 3}
iris_raw_data['class'] = iris_raw_data['class'].apply(lambda x:Iris_dir[x])
# 训练数据 X
iris_data = iris_raw_data.values[:, :-1]
# 标签 y
y = iris_raw_data.values[:, -1]
# 用 MGD 训练的参数
start = time.time()
theta_MGD = MGD_train(iris_data, y)
run_time = time.time() - start
y_pred_MGD = GD_predict(iris_data, theta_MGD)
print("MGD训练1000轮得到的准确率{:.2f}% 运行时间是{:.2f}s".format(calc_accuracy(y, y_pred_MGD), run_time))
# 用 SGD 训练的参数
start = time.time()
theta_SGD = SGD_train(iris_data, y)
run_time = time.time() - start
y_pred_SGD = GD_predict(iris_data, theta_SGD)
print("SGD训练1000轮得到的准确率{:.2f}% 运行时间是{:.2f}s".format(calc_accuracy(y, y_pred_SGD), run_time))
# 用 MBGD 训练的参数
start = time.time()
theta_MBGD = MBGD_train(iris_data, y)
run_time = time.time() - start
y_pred_MBGD = GD_predict(iris_data, theta_MBGD)
print("MBGD训练1000轮得到的准确率{:.2f}% 运行时间是{:.2f}s".format(calc_accuracy(y, y_pred_MBGD), run_time))
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: MATLAB中非线性回归梯度下降是一种针对非线性回归问题的优化算法。该算法的目的是最小化预测值与实际值之间的误差,以此来确定最佳的参数组合,从而实现对未知数据的精准预测。 该算法的核心是梯度下降法,它基于损失函数,即预测值与实际值之间的差异来进行参数更新。在每一次迭代中,梯度下降法都会计算损失函数的偏导数,然后根据导数值和学习率来更新模型中的参数。在多次迭代中,模型会不断地调整参数,以尽可能地减少损失函数的值,从而使预测值更加准确。 非线性回归梯度下降算法的优点在于能够快速地逼近最优解,同时它适用于各种不同的非线性模型。然而,该算法存在一些缺点,例如随着参数的增加,运算时间和计算成本都会增加,同时为了达到较高的精度,需要进行大量的迭代操作,因此计算速度也会受到影响。 总之,非线性回归梯度下降是一种高效的算法,适用于大部分复杂的非线性模型,可以帮助人们更好地理解数据,并精准地进行预测。 ### 回答2: MATLAB是一种常用的数学软件,它提供了非线性回归梯度下降算法的实现。非线性回归梯度下降是一种优化算法,它可以通过调整模型参数来最小化误差函数。在非线性回归问题中,通常使用的误差函数是平方误差。梯度下降算法的核心思想是在每一次迭代中,基于误差函数的梯度来更新模型参数,以便在下一次迭代中获得更好的结果。这个过程可以持续多次,直至误差函数收敛到最小值。 非线性回归问题通常比线性回归问题更具挑战性,因为它们的函数形式没有简单的解析形式。在这种情况下,我们必须使用数值方法来确定函数中的参数。非线性回归梯度下降算法是一种常见的数值优化方法,它在每一次迭代中使用梯度下降算法来确定模型参数。在MATLAB中,可以使用fminsearch函数实现非线性回归梯度下降算法。此函数接收一个函数句柄,参数向量以及其他优化参数,并返回一个包含最优参数的向量和相关的误差值。 需要注意的是,非线性回归梯度下降算法的结果可能会受到初始参数值的影响。因此,在使用此算法时,需要进行多次试验,并使用不同的初始参数值来寻找最佳结果。此外,由于算法的收敛速度取决于参数的选择以及数据集的大小等因素,因此需要进行一些实验以确定最佳的参数设置。 ### 回答3: 梯度下降法是一种优化算法,可用于非线性回归模型的参数估计。在MATLAB中,可以使用“fminsearch”函数实现此算法。该函数需要两个输入参数:第一个是函数句柄,指定要进行优化的目标函数;第二个是初始参数值向量,指定优化算法从哪里开始搜索。目标函数应该是一个返回优化值(通常是均方误差或极大似然估计)的函数,并且需要将当前参数作为输入。 在实践中,使用梯度下降算法时,需要调整以下几个参数:学习率、迭代次数和优化算法的初始参数。较小的学习率可以增加函数的收敛性,但可能会减缓优化速度。迭代次数的选择应该基于分配的资源和问题的复杂性。通常使用较少的迭代次数并观察结果,以确定是否需要增加迭代次数。最初的参数值应该在可能的参数空间内随机选择,以避免优化过程中梯度下降陷入局部最优解。 总的来说,MATLAB的梯度下降法对于非线性回归问题是非常实用的。在选择算法参数时,需要适当平衡函数收敛速度和准确性,以获得最佳拟合结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小威程序员

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

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

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

打赏作者

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

抵扣说明:

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

余额充值