第二周 单变量线性回归实战

本文介绍了如何使用单变量线性回归进行编程实践,重点讨论了不同学习率对收敛速度的影响。通过实验,作者发现学习率大小对收敛速度至关重要,过小的学习率会导致迭代次数增多,而过大的学习率则可能导致无法收敛。
摘要由CSDN通过智能技术生成

因为第一周是大致介绍了什么是机器学习以及机器学习的分类等。有时间把这个笔记总结补上。让我们一起来进入单变量线性回归的实战吧。这个基础是已经学习完理论知识啦。

先来看看作业的题目:

编写线性回归的程序

   1.比较不同学习率下收敛速度的不同

    2.比较不同方法的收敛过程

对于这个题目,大致整理一下我们的思路。

1.确定数据集,数据集可视化,

2.确定单变量的函数为h_{\Theta }\left ( x \right )=\Theta _{0}+\Theta _{1}x,更新\Theta _{0},\Theta _{1}

3.通过损失函数J\left ( \Theta \right )=\frac{1}{2m}\sum_{i=1}^{m}\left ( h_{\Theta } \left ( x^{\left ( i \right )} \right )-y^{\left ( i \right )}\right )^{2},来评价模型好坏

4.采用随机梯度下降,设置不同的学习率来观察收敛速度

5.采用正规方程解除最优解,与梯度下降法得到的最优解比较。

下面就是具体的操作步骤:

1.数据集

  首先,大家可以去网上自己下载真实的数据集,这里因为笔者找了很多数据集下载都要付费,其中sklearn自带的数据集需要做数据处理,这个目前笔者还没有学过,而且这个作业也还有其他的方法写出来就没有用啦。如果有想用这个数据集的读者,可以去我的主页寻找加载数据集的方法,很多博客上也都讲的很清楚,大家可以自己寻找,参考。

  这里笔者使用的是自己用随机数生成的方法来制作了一个数据集,具体的函数使用就不一一介绍了,大家可以查一下,代码及运行结果如下:

# 初始化训练样本
data_num = 50
x = np.array(np.random.randint(0, 50, data_num))#随机生成50个数字为一个一行矩阵
#y=3x+5,后面加的是噪点,噪点不宜过大
y = np.array(3 * x + 5 + np.random.randint(0, 2, data_num))


#下面是数据集可视化的代码,作为调试内容,可以看到画出的散点图是有一次函数的趋势的
plt.scatter(np.array(x),np.array(y))
plt.show()

2.确定参数

创建一个1×2的矩阵来存储参数,并对参数进行初始化。

 #参数初始化  y=1x+1
 theta=np.matrix([1.0,1.0])

注意:这里初始化一定要用浮点数,如果写的是整数,那么就会默认是整数,在后续的计算中很不精确,甚至完全不会收敛。

3.损失函数

我们先来看一下损失函数的公式:

J\left ( \Theta \right )=\frac{1}{2m}\sum_{i=1}^{m}\left ( h_{\Theta } \left ( x^{\left ( i \right )} \right )-y^{\left ( i \right )}\right )^{2}

在这里,我们对于数据的存储都是矩阵的形式,而且矩阵对于这种批量的运算很友好。所以接下来让我们分析一下,把这个公式写成矩阵的形式是怎么样的。下面手写的是伪代码,方便理解。

由上面的分析我们可知,x矩阵需要变为列矩阵,并且要在之前加入元素全部为1的列。thera参数矩阵也要变为2×1的矩阵,只需将thera矩阵转置即可,而得到的h_{\Theta }\left ( x \right )是50×1的矩阵,而y矩阵是1×50的矩阵。所以也需要把h_{\Theta }\left ( x \right )也转置一下再进行减法运算。具体代码如下:

#使矩阵可以运算
 one=np.ones(x.shape)
 x_train=np.c_[one,x]
 theta=theta.T


#上方的代码是写在主函数中的
#下方代码是将损失函数的运算也为子函数,方便调用
#代价函数 
def costFuntion(x,y,theta):
    result = np.power((np.dot(x,theta).T - y),2)
    num=np.size(result)
    return np.sum(result)/(2* num)

4.梯度下降法

梯度下降法的原理在这里就不多赘述了,理论部分可以看我上传的资源。这里我们直接来看随机梯度下降法的公式:

\Theta _{j}=\Theta _{j}-\alpha \frac{\partial }{\partial \Theta _{j}}J\left ( \Theta _{0},\Theta _{1} \right )

这里是的\alpha是学习率,是我们要设置的超参数。这个公式的难点是:对损失函数对\Theta求偏导,对\Theta _{0}求偏导时,\Theta _{1}看作常数。对\Theta _{1}求偏导时,\Theta _{0}看作常数。这个是一个数学知识。我们来看看把公式分开来写是怎么样的。

其中关于h_{\Theta }\left ( x^{i} \right )-y^{i}的运算在损失函数部分相信大家已经懂了,不懂可以反复观看。

根据这个公式,我们可以看出,两个参数的更新公式是不一样的,所以我是分开来更新的。

其中更新的过程用一个for循环来完成,更新次数也可以作为一个参数自己设置。中间循环的过程中我们可以打印当时的参数,画出我们预测的直线来观察收敛过程。

同时,我们的数据集噪声是0.2的误差,我们在损失函数值小于0.2的时候就停止迭代。

具体请看代码:

def gradient (x,y,theta,lr,time):
    #使用k,b比较方便,大家也可以直接用theta【0】,和theta【1】来更新
    b=theta[0]
    k=theta[1]
    cost=costFuntion(x,y,theta)
    print("迭代前各参数为:第一个参数为:%f,第二个参数为:%f,损失函数值为:%f"%(theta[0],theta[1],cost))
    for i in range(time):
        a=np.array(np.dot(x,theta).T - y)
        num=np.size(y)
        k=k-lr*np.sum(np.dot(a,x))/num
        b=b-lr*np.sum(a)/num
        # print("k=%f"%k)
        # print("b=%f"%b)
        theta[0]=b
        theta[1]=k
        cost=costFuntion(x,y,theta)
        print("第%d次迭代,此时第一个参数为:%f,第二个参数为:%f,损失函数值为:%f"%(i+1,theta[0],theta[1],cost))



        # 每次迭代完成后画图
        y_predict=np.dot(x,theta)
        plt.plot(np.array(x[:,1]),np.array(y_predict))
        plt.scatter(np.array(x[:,1]),np.array(y))
        plt.show()

        if cost<0.2 :
             print("第%d次迭代,此时第一个参数为:%f,第二个参数为:%f,损失函数值为:%f"%(i,theta,[0],theta[1],cost))
             print("误差满足条件,停止迭代")
             break
    return k,b

#下面的是写在主函数里面
gradient(x_train,y,theta,0.0018,5000)#学习率为0.0018,迭代次数为5000

5.运行结果分析

到这里我们来回答作业中的第一个问题,不同学习率的收敛速度。

随机梯度下降法全部代码如下:

此时学习率为0.0018,迭代次数为2000

import numpy as np
import matplotlib.pyplot as plt


#代价函数 
def costFuntion(x,y,theta):
    result = np.power((np.dot(x,theta).T - y),2)
    num=np.size(result)
    return np.sum(result)/(2* num)

#梯度下降法
def gradient (x,y,theta,lr,time):
    #使用k,b比较方便,大家也可以直接用theta【0】,和theta【1】来更新
    b=theta[0]
    k=theta[1]
    cost=costFuntion(x,y,theta)
    # print("迭代前各参数为:第一个参数为:%f,第二个参数为:%f,损失函数值为:%f"%(theta[0],theta[1],cost))
    for i in range(time):
        a=np.array(np.dot(x,theta).T - y)
        num=np.size(y)
        k=k-lr*np.sum(np.dot(a,x))/num
        b=b-lr*np.sum(a)/num
        # print("k=%f"%k)
        # print("b=%f"%b)
        theta[0]=b
        theta[1]=k
        cost=costFuntion(x,y,theta)
        print("第%d次迭代,此时第一个参数为:%f,第二个参数为:%f,损失函数值为:%f"%(i+1,theta[0],theta[1],cost))



        # # 每次迭代完成后画图
        # y_predict=np.dot(x,theta)
        # plt.plot(np.array(x[:,1]),np.array(y_predict))
        # plt.scatter(np.array(x[:,1]),np.array(y))
        # plt.show()

        if cost<0.2 :
             print("第%d次迭代,此时第一个参数为:%f,第二个参数为:%f,损失函数值为:%f"%(i,theta,[0],theta[1],cost))
             print("误差满足条件,停止迭代")
             break
    return k,b



if __name__ != '__main__':
    pass
else:
        # 初始化训练样本
        data_num = 50
        x = np.array(np.random.randint(0, 50, data_num))
        y = np.array(3 * x + 5 + np.random.randint(0, 2, data_num))
        # print(x.shape)
        # print(x)
        # print(y)
        # print(x.shape)
        # print(y.shape)
        # plt.scatter(np.array(x),np.array(y))
        # plt.show()

        #参数初始化  y=1x+1
        theta=np.matrix([1.0,1.0])

        #使矩阵可以运算
        one=np.ones(x.shape)
        x_train=np.c_[one,x]
        theta=theta.T

        # e=costFuntion(x,y,theta)  
        # print(e)
        # theta[1],theta[0]=
        gradient(x_train,y,theta,0.0018,5000) 

运行结果如下:

可以看出,在第3094次迭代时,损失函数值小于0.2,就跳出了循环。

让我们来修改学习率,改为0.003的时候,结果时怎么样的。

可以看出,每次迭代之后,损失函数的值变大,最后并没有收敛,说明我们给的学习率太大了。

现在我们在0.0018的基础上减小学习率,把学习率设置成0.001,迭代次数仍为5000,看看运行结果怎么样。

可以看出,在5000次迭代之后,损失函数还没有达到我们想要的目标值。

以上两个例子说明,说明学习率越小,迭代的需要的次数和时间越久。但是学习率太大的话,是没有办法收敛的。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值