吴恩达机器学习作业1--线性回归


一、知识点概况

线性回归问题指的是给你一堆散点,把这些散点拟合成一条直线。解决线性回归问题又有两个方法:最小二乘法和梯度下降法。

(一)最小二乘法计算

把散点拟合成的一条直线记为y=kx+b。(x,y)表示的是点的坐标,k和b是未知参数。定义代价函数如下:
在这里插入图片描述
公式中的h(x)的表达式如下:
在这里插入图片描述
我们需要调整Θ0和θ1的值使得Cost值最小(这两个参数对应代码中的b和k),这就需要用到最小二乘法了。
还可以用矩阵形式的最小二乘法求参数。(只是形式和上面公式不同,目的和结果是一致的)
在这里插入图片描述
x是由变量组成的一个向量,y是当x选取这一组变量值的时候的取值。对于单变量回归问题,假设有m条数据(也就是有m组(x,y)这样的坐标点),那么x就是一个m x 1的向量,y是一个m x 1的向量。我们在使用公式之前需要对x先处理,将x中最左边添加一列,这一列的值全是1。处理过后,x就是一个m x 2的向量了。利用上面的公式,可以得到θ。单变量回归问题得到的θ是一个2 x 1的向量。也就对应着θ0和θ1。

(二)梯度下降法

梯度下降法相比最小二乘法,它需要执行一个学习率α,学习率α不能太大也不能太小,如果学习率α过小,对最终结果是不影响的,但是会影响收敛的速度,α小也就表示步长很短,每次的变化不是很大,知道迭代次数够,最终的结果是正确的。而学习率α过大会导致无法收敛的情况出现。如下所示:
在这里插入图片描述
12345表示每次迭代的结果,初始从点1开始。出现这样的结果的原因可以结合下面的梯度下降公式分析。当学习率不变的时候,如果当学习率设置过大,这回导致直接跨越最低点,从点1变成点2。而梯度下降公式中学习率后面乘的表达式含义为斜率,点1斜率的绝对值是小于点二斜率的绝对值,所以点2和点3之间的跨度一定是大于点1和点2的跨度的。所以会导致越迭代越远离收敛点的情况出现。(注意不是震荡收敛到最低点!!!)所以学习率的设置一定不能太大,最好不要太小,可以多设置几次看看效果。

梯度下降公式如下:
在这里插入图片描述
α是学习率,j的取值是0或1。Θ0和Θ1分别对应b和k,这和上面最小二乘法是一致的。J(Θ0,Θ1)是代价函数。

类似地,梯度下降法也有矩阵实现方法,公式如下:(只是形式和上面公式不同,目的和结果是一致的)
在这里插入图片描述
公式中的w其实就是θ。对于x的处理和最小二乘法相同,需要现在最左侧补一列1。

二、单变量线性回归代码

(一)最小二乘法

最小二乘法有两种实现方式,第一种就是调库,第二种使用矩阵实现

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import leastsq


def func(p,x):
    k,b=p
    return k*x+b

def error(p,x,y):
    return func(p,x)-y #x、y都是列表,故返回值也是个列表


if __name__ == '__main__':

    data1=[]
    with open('ex1data1.txt','r')as f:
        for line in f.readlines():
            line=line.split('\n')[0]
            first=line.split(',')[0]
            second = line.split(',')[1]
            data1.append([first,second])

    #print(data1)

    data1_x=[]
    data1_y=[]
    for i in data1:
        data1_x.append(float(i[0]))
        data1_y.append(float(i[1]))

    plt.plot(data1_x,data1_y,'o',label='Origin Data',c='blue')


    p0 = [1, 2]  #k和b的初始值,可以随意取
    #leastsq是最小二乘法的python库,可以直接调用
    Para = leastsq(error,p0,args=(np.array(data1_x),np.array(data1_y)))
    k, b = Para[0]
    newx=np.linspace(min(data1_x),max(data1_x),1000)
    newy=k*newx+b
    plt.plot(newx,newy,color="orange",label="Predict",linewidth=2)

    plt.legend(loc=2)
    plt.show()
    print(k,b)
    #最小二乘法得到的k为1.1930336448308296,b为-3.895780885333545

如果使用最小二乘法的矩阵表示,代码如下:

#矩阵乘积方法实现最小二乘法
    m = len(data1_x)
    a = np.ones((m, 1))
    x = np.column_stack((a, data1_x))
    newx_inv = np.linalg.inv((x.T).dot(x))
    temp = newx_inv.dot(x.T)
    y = np.array(data1_y)
    y = y.reshape(len(y), 1)
    paramater=temp.dot(data1_y)
    k=paramater[1]
    b=paramater[0]
#[[-3.89578088][ 1.19303364]]  这是向量计算的结果

利用最小二乘法拟合散点得到的结果如下:
在这里插入图片描述

(二)梯度下降法

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import leastsq


def func(p,x):
    k,b=p
    return k*x+b

def error(p,x,y):
    return func(p,x)-y #x、y都是列表,故返回值也是个列表


if __name__ == '__main__':
    plt.rcParams['font.sans-serif'] = ['SimHei']
    data1=[]
    with open('ex1data1.txt','r')as f:
        for line in f.readlines():
            line=line.split('\n')[0]
            first=line.split(',')[0]
            second = line.split(',')[1]
            data1.append([first,second])

    #print(data1)

    data1_x=[]
    data1_y=[]
    for i in data1:
        data1_x.append(float(i[0]))
        data1_y.append(float(i[1]))

    plt.plot(data1_x,data1_y,'o',label='Origin Data',c='blue')

    alpha = 0.01 #学习速率
    iterations = 10000 #梯度下降的迭代轮数
    theta = [0, 0] #初始化theta,即k和b
    m = len(data1_x)
    for i in range(iterations):
        temp0 = theta[0]   #temp对应b
        temp1 = theta[1]   #temp对应k
        for j in range(m):
            temp0 -= (alpha / m) * (theta[0] + theta[1] * data1_x[j] - data1_y[j])
            temp1 -= (alpha / m) * (theta[0] + theta[1] * data1_x[j] - data1_y[j]) * data1_x[j]
        theta[0] = temp0
        theta[1] = temp1

    x = [5.0, 22.5]
    y = [5.0 * theta[1] + theta[0], 22.5 * theta[1] + theta[0]]
    plt.plot(x, y, color="red",label='梯度下降法预测')

    plt.legend(loc=2)
    plt.show()
    print(theta) #k为1.1930336383584847,b为-3.8957808202682447

基于梯度下降法拟合散点得到的结果如下:
在这里插入图片描述

三、多变量线性回归代码

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

data = np.loadtxt('ex1data2.txt', delimiter=',')
x = data[:, 0:2] #这个范围是左闭右开的
y = data[:, 2]
m = y.size

'''特征放缩——均值归一化'''
def norm(x):
    sigma = np.std(x, axis=0) # axis=0计算每一列的标准差,=1计算行的  
    mu = np.mean(x, axis=0)
    x = (x-mu)/sigma
    return x, mu, sigma

x, mu, sigma = norm(x) 
x = np.c_[np.ones(m), x] #矩阵合并,第一列加1

'''梯度下降法'''
theta = np.zeros(3) #初始化theta的值
num_iteration = 100 #初始化迭代次数
alpha = 1 #初始化学习速率
J = np.zeros(num_iteration)

#定义代价函数
def costfun(theta, x=x, y=y, m=m): 
    h_x = x@theta #假设函数的shape是(47,3)
    return np.sum((h_x-y)**2)/(2*m) 

#迭代
def gradient_descent(theta, alpha):
    for i in range(num_iteration):
        J[i]=costfun(theta) #将每次迭代的代价函数值计入
        theta = theta-(alpha/m)*(x.T@(x@theta-y))
    return theta

theta = gradient_descent(theta, alpha)

'''正规方程法'''
theta = np.linalg.inv(x.T@x)@x.T@y #求矩阵的逆

四、总结

线性回归有两种实现方法,第一种就是最小二乘法,第二种是梯度下降法。在处理多特征值的时候,需要注意的是梯度下降法是一定需要预处理特征值的,先把特征值的范围都调整到[0,1]中,再进行计算。最小二乘法可以不预处理,直接计算(也可以预处理)。另外在代码实现过程中,可以通过矩阵形式来实现这两种算法,更方便。最后比较一下这两种方法,最小二乘法的有点列式简单,但是当特征值较多的时候效果不好,运行时间太长。这里的较多一般来说在特征值小于10000个的时候,最小二乘法比较不错,大于10000的话,还是用梯度下降法吧。这个阈值也不绝对,但一般是这样的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值