线性回归

1.引言:

看了Stanford的Andrew Ng老师的机器学习公开课中关于Logistic Regression的讲解写下此篇学习笔记总结一下。

 

2.原理:

按照我们老师的话说,做机器学习无非是三个重点:取模型,选代价函数,找极值

取模型:

找一个合适的预测函数(Andrew Ng的公开课中称为hypothesis),一般表示为h函数,该函数就是我们选取的模型,它用来预测输入数据的判断结果。这个过程时非常关键的,需要对数据有一定的了解或分析,知道或者猜测预测函数的“大概”形式,比如是线性函数还是非线性函数。如果对于一组数据,我们找不到相应的模型来描述,那么我们无法进行下去。

线性模型就是预测的y=\theta 1x1+\theta 2x2+\cdot \cdot \cdot +\theta nxn+c的形式,这种形式可以用矩阵表示,即Y=θX+C(其中θ,X都为矩阵)

非线性模型就是出现了x的多次方

 

选代价函数:代价函数就是能表示样本的预测值h和实际值y 差值得一个函数,

代价函数有cost函数和J函数两种说法

J=\sum_{i=1}^{m}Cost()

cost函数主要是单个样本的差值,J函数就是对所有样本的Cost进行求和或取平均值

因为我们说的代价是所有样本的,所以J函数才是我们的代价函数

 

找极值:显然,J(θ)函数的值越小表示预测函数越准确(即h函数越准确),所以这一步需要做的是找到能使J(θ)函数的最小的θ值。我们选取的算法几乎是梯度下降算法或者一些变换形式,可以说没有梯度下降就没有现在的深度学习,这是一个神奇的算法。但是缺陷在于只能找到极小值,这要求我们在J函数的选取是要注意J函数只有一个极小值(即要求J函数能收敛)

 

 

3.具体实现过程:

找预测函数:

假设我们来预测房价和面积的关系:

我们可以画出一条绿色的直线来描述这个关系,这台直线的函数式即为{\color{Red} y=\theta1x1+\theta0 },这个即为我们的假设函数h,为了区别于实际的房价值,我们把我们通过h函数预测出来的y值称为h。

 

取代价函数:(m是样本数)

我们肯定希望找到的那条线,距离每个点都很近,最好所有的点上都在这条线上,但是一条直线去拟合所有的点都在这条直线上肯定不现实,所以我们希望这些点尽量离这条直线近一点。

所以我们会想到垂直距离,但是垂直距离的公式比较复杂,所谓我们选取了(h-y)^{^{2}}作为我们的cost函数,这在图形上的意义即是竖直距离,当cost函数越小时,这条直线离这个点越近,当cost=0时,点就在直线上。

然后我们再取所有样本的平均值(再除以2的原因是求导抵消了,这个就相当于常数c,),

那么我们的总误差即J函数为:J=(1/2m)\sum_{i=1}^{m}cost=(1/2m)\sum_{i=1}^{m}(h-y)^2

 

找极值:

首先我们要明确找的是什么,我们要找的即使J函数最小的一组θ值,在这个问题中,即为θ0,θ1.

所以我们的步骤为:

1.随机开始一组theta值,我们一般取0或1之类的

2.利用梯度下降算法改变theta的值直到一个合适的值(即迭代)

\theta 1=\theta 1-\alpha (\partial J(\theta1)/\partial(\theta1))

展开即为\theta 1=\theta 1-\alpha* \sum_{i=1}^{m}((1/m)*(h-y)*x))   


  首先来讲一下梯度下降算法(有一些博客也叫梯度上升,因为他们求导后把负号号移出去了):

    不管我们位于这个什么位置,只要我们想走到极小点,就要往梯度方向(导数)的反方向走,假如我们一开始在左边的圆点处,那我们一点一点往右边滑下去呗,即为\theta 1=\theta 1-\alpha (\partial J(\theta1)/\partial(\theta1)).

     α为步长,这个控制我们每次移动的距离

      我们重复这个过程(\theta 1=\theta 1-\alpha (\partial J(\theta1)/\partial(\theta1)),就能够到达极小点附近(而不是最小点)

 

大多数同学会有疑问,如果越过了最低点怎么样:即使越过了最低点,我们对该点求导,发现该店的导数为正,减去即为往左边移动。而且一般α取得合理就不会越过,因为越到下面导数越小,就像2-1-(1/2)-(1/4)-(1/8)-......-(1/2^n)一样永远大于0

 

    接下来讲下α的作用和怎么选取合适的α:

    如左图所示,首先我们随机选取了θ1为靠近最小值的圆点,假如我们选取了一个较大的α,那么我们减去了一个比较大的值,导致我们第一次移动到了最小值的右边,我们求导发现该点的导数更大,这就导致了我们第二次移动到原来那个点的左边,然后该点的导数更大,这就导致了每一次迭代不是想更小的移动,而是像更大的移动,这样就到不了最小值了。

   当然α也不是越小越好,太小了,移动的太慢了,迭代500次可能还没有算出来,一个合适的α迭代100后就很接近极小值了

   我们一般选取α为0.01,但是对于不同的数据,不同的代价函数,这个值会不一样,我们可以通过30倍的缩放来改变这个值

 

为什么梯度下降算法要求J函数只有一个极小值:

对于以上的J函数,假如我们选取不同的初始值θ0和θ1,那么我们将会到达不同的极小值,最后我们怎么确定哪个最小呢,有多少个最小的呢,所以我们在选取J函数的时候就要确保J函数只有一个极小值,即下面这样的图形

 

最后就直接上代码:

import numpy as np
import pylab
import json

def compute_error(b,m,data):
    """计算代价函数"""
    cost=0
    x=data[0]
    y=data[1]
    x=np.array(x)
    y=np.array(y)
    num=float(len(data))
    cost=(m*x+b-y)**2
    cost=np.sum(cost,axis=0)
    cost=cost/(2*num)
    return cost

def optimizer(data,starting_b,starting_m,learning_rate,num_iter):
"""梯度下降算法"""
    b=starting_b
    m=starting_m

    for i in range(num_iter):
        b,m=compute_gradient(b,m,data,learning_rate)
        if i%100==0:
            print(str(i)+" error:"+str(compute_error(b,m,data)))
            plot_data(data,b,m)
   
    return [b,m]

def compute_gradient(b_current,m_current,data,learning_rate):
"""每一次的迭代"""
    b_gradient = 0
    m_gradient = 0
    num=float(len(data))

    # x=data[:,0]
    # y=data[:,1]
    x=data[0]
    y=data[1]
    x=np.array(x)
    y=np.array(y)

    b_gradient=(m_current*x+b_current-y)*(1/num)#先前无法收敛在于偏导b和m的偏导写反了
    b_gradient=np.sum(b_gradient,axis=0)

    m_gradient=(m_current*x+b_current-y)*x*(1/num)
    m_gradient=np.sum(m_gradient,axis=0)

    m_new=m_current-(learning_rate*m_gradient)
    b_new=b_current-(learning_rate*b_gradient)

    return [b_new,m_new]

def plot_data(data,b,m):
""""画曲线"""
    x=data[0]
    y=data[1]
    x=np.array(x)
    y=np.array(y)
    y_predict = m*x+b
    pylab.plot(x,y,'o')#原来的元素
    pylab.plot(x,y_predict,'k-')#预测的元素
    pylab.show()

def linear_regression():
    starting_b=0.0
    starting_m=0.0
    learning_rate=0.00001#学习步数太小拟合慢,太大就会不能convergence
    #数据的大小会决定α,这次数据扩大了100倍,使用α要缩小100倍,标准化也行
    num_iter=500
    x=[63.030301,25.60160963,84.07966543,33.21034955,80.36386821,83.07007084,73.82586473,91.57007003,10.92153202,84.7031311,24.39083948,61.10565706,56.9543926,87.40964666,71.43630822,66.23807235,12.34436146,93.93842171,14.53165794,78.2440026]
    y=[63.87392259,26.29752231,85.14718359,34.06340079,81.33633071,83.85031798,75.08598548,92.85616524,12.43963086,85.56767789,25.40299684,62.18816348,57.7284949,88.24736608,72.85552885,66.93011168,13.14443623,95.47745258,15.50435747,79.81954144]
    data=[x,y]
    print("first error:"+str(compute_error(starting_b,starting_m,data)))

    [b,m]=optimizer(data,starting_b,starting_m,learning_rate,num_iter)

    print("last error:"+str(compute_error(b,m,data)))
    print(str(m))
    print(str(b))
    plot_data(data,b,m)
linear_regression()

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值