线性回归(最小二乘法和梯度下降)

一、定义与公式

线性回归(Linear regression)是一种线性模型,利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式。

  • 具体来说,利用线性回归模型,可以从一组输入变量x的线性组合中,计算输出变量y。
  • 只有一个自变量的情况称为单变量回归,大于一个自变量情况的叫做多元回归

那么怎么理解呢?我们来看几个例子

  • 期末成绩:0.7×考试成绩+0.3×平时成绩
  • 房子价格 = 0.02×中心区域的距离 + 0.04×城市一氧化氮浓度 + (-0.12×自住房平均房价) + 0.254×城镇犯罪率

上面两个例子,我们看到特征值与目标值之间建立的一个关系,这个可以理解为回归方程

多元线性回归

如果有两个或两个以上的自变量,这样的线性回归分析就成为多元线性回归。

实际问题中,一个现象往往是受到多个因素影响的,所以多元线性回归比一元线性回归的实际应用更广。

二、最小二乘法

线性回归模型的关键就是确定w和b。w和b学得之后,模型也就确定了。

那么该如何确定w和b?

假设输入特征只有一个。

使f(x)与y之间的均方误差最小

 试图找到一条直线,使得所有样本到直线上的欧式距离之和最小,这就是最小二乘法。

基于均方误差最小化来进行模型求解的方法称为“最小二乘法”(least square method)。

它的主要思想就是选择未知参数,使得理论值与观测值只差的平方和达到最小。

2.1 公式推导

使得

最小化的过程,称为线性回归模型的“最小二乘参数估计”,分别对w和b求偏导。

推导过程参见南瓜书:https://datawhalechina.github.io/pumpkin-book/#/chapter3/chapter3

 令偏导数都等于0

 

 

 

2.2 代码实现

数据集:https://files.cnblogs.com/files/wkfvawl/data.rar

import numpy as np
import matplotlib.pyplot as plt
#导入数据
# delimiter 分隔符
points = np.genfromtxt('data.csv', delimiter=',')
# 提取points中的两列数据,分别作为x,y
# 每行的第一个和每行的第二个
x = points[:, 0]
y = points[:, 1]
# 先定义一个求均值的函数
def average(data):
    sum = 0
    num = len(data)
    for i in range(num):
        sum += data[i]
    return sum/num

# 定义核心拟合函数
def fit(points):   
    M = len(points)
    #x均值    
    x_bar = average(points[:, 0])
    #求w     
    sum_yx = 0
    sum_x2 = 0
    sum_delta = 0
    for i in range(M):
        x = points[i, 0]
        y = points[i, 1]
        sum_yx += y * ( x - x_bar )
        sum_x2 += x ** 2
    # 根据公式计算w
    w = sum_yx / ( sum_x2 - M * (x_bar**2) )
    #求b
    for i in range(M):
        x = points[i, 0]
        y = points[i, 1]
        sum_delta += ( y - w * x )
    b = sum_delta / M
    return w, b

# scatter散点图
plt.scatter(x, y)
# 针对每一个x,计算出预测的y值
pred_y = w * x + b
# plot线型图
plt.plot(x, pred_y, c='r')
plt.show()

三、梯度下降

最小二乘法在面对大量数据时,太慢了,可以使用凸优化中最常见的梯度下降法进行优化。

梯度下降是一个用来求函数最小值的算法,我们将使用梯度下降算法来求出损失函数𝐽(𝜃0, 𝜃1) 的最小值。
梯度下降背后的思想是:开始时我们随机选择一个参数的组合(𝜃0, 𝜃1, . . . . . . , 𝜃𝑛),计算代价函数,然后我们寻找下一个能让代价函数值下降最多的参数组合。我们持续这么做直到到到一个局部最小值(local minimum),因为我们并没有尝试完所有的参数组合,所以不能确定我们得到的局部最小值是否便是全局最小值(global minimum),选择不同的初始参数组合,可能会找到不同的局部最小值。

3.1 公式推导

一元线性回归

在多元线性回归中

α为学习速率,需要手动指定(超参数),α旁边的整体表示方向

沿着这个函数下降的方向找,最后就能找到山谷的最低点,然后更新𝜃值

我们可以通过α来控制步长,大不能太大也不能太小。

在多元线性回归中,选择损失函数

这里

 

梯度下降算法

 

 

3.2 代码实现

import numpy as np
import matplotlib.pyplot as plt
# 模型超参数
alpha = 0.0001
# 初始值
initial_w = 0
initial_b = 0
# 迭代次数
num_iter = 10
# 导入数据
points = np.genfromtxt('data.csv', delimiter=',')

# 损失函数是系数的函数,另外还要传入数据的x,y
def compute_cost(w, b, points):
    total_cost = 0
    M = len(points)
    # 逐点计算平方损失误差,然后求平均数
    for i in range(M):
        x = points[i, 0]
        y = points[i, 1]
        total_cost += ( y - w * x - b ) ** 2
    return total_cost/M
# 核心算法
def grad_desc(points, initial_w, initial_b, alpha, num_iter):
    w = initial_w
    b = initial_b
    # 定义一个list保存所有的损失函数值,用来显示下降的过程
    cost_list = []
    # 迭代     
    for i in range(num_iter):
        cost_list.append( compute_cost(w, b, points) )
        w, b = step_grad_desc( w, b, alpha, points )
    # 迭代结束 获得最优w b        
    return [w, b, cost_list]

def step_grad_desc( current_w, current_b, alpha, points ):
    sum_grad_w = 0
    sum_grad_b = 0
    M = len(points)
    # 对每个点,代入公式求和
    for i in range(M):
        x = points[i, 0]
        y = points[i, 1]
        h = current_w * x + current_b - y
        sum_grad_w += h * x
        sum_grad_b += h - y
    # 用公式求当前梯度
    grad_w = 2/M * sum_grad_w
    grad_b = 2/M * sum_grad_b
    # 梯度下降,更新当前的w和b
    updated_w = current_w - alpha * grad_w
    updated_b = current_b - alpha * grad_b
    return updated_w, updated_b

测试:运行梯度下降算法计算最优的w和b

w, b, cost_list = grad_desc( points, initial_w, initial_b, alpha, num_iter )

print("w is: ", w)
print("b is: ", b)

cost = compute_cost(w, b, points)

print("cost is: ", cost)

plt.plot(cost_list)
plt.show()
w is:  1.47513229374931
b is:  0.17505959562572973
cost is:  112.56579741946545

画出拟合曲线

plt.scatter(x, y)
# 针对每一个x,计算出预测的y值
pred_y = w * x + b

plt.plot(x, pred_y, c='r')
plt.show()

posted @ 2021-11-16 15:04  王陸  阅读(693)  评论(0编辑  收藏  举报