机器学习笔记03线性回归

如果只包括⼀个⾃变量(特征x)和⼀个因变量(标签y),且两者的关系可⽤⼀条直线近似表示,这种回归分析就称为⼀元线性回归分析。如果回归分析中包括两个或两个以上的⾃变量,且因变量和⾃变量之间是线性关系,则称为多元线性回归分析。

机器学习步骤:

  1. 问题定义
  2. 数据的收集和预处理 (读取,可视化,相关分析,散点图,数据集清洗和规范化,拆分数据集为训练集和测试集,数据归一化)

相关分析⽤⼏⾏代码即可实现,并可以⽤热⼒图(heatmap)的⽅式⾮常直观地展示出来#对所有的标签和特征两两显示其相关性的热⼒图 sns.heatmap(df_ads.corr(), cmap="YlGnBu", annot = True)
df_ads.corr()作用:计算 DataFrame df_ads 中所有数值型列之间的 皮尔逊相关系数(Pearson correlation coefficient)

#显示销售额和各种⼴告投放⾦额的散点图 sns.pairplot(df_ads,	
x_vars=['wechat',	'weibo',	'others'],	y_vars='sales',	height=4,	aspect=1,	kind='scatter')

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.2, random_state=0)
Sklearn中的train_test_split函数,是机器学习中拆分数据集的常⽤⼯具。test_size=0.2,表示拆分出来的测试集占总样本量的20%。

  1. 选择机器学习模型(什么模型,什么参数)

假设函数:到最佳的函数f(x)之前,现有的函数模型不⼀定是很准确的。 机器学习的具体⽬标就是确定假设函数h(x)。线性回归的假设函数为h(x)=wx+b

损失:当前预测值和真实值之间的差距。模型好不好还不能仅看单个样本,⽽是要针对所有数据样本找到⼀组平均损失“较⼩”的函数模型。

在这里插入图片描述

损失函数(loss function)L(w,b)就是⽤来计算平均损失的。损失函数L是参数w和b的函数,计算预测值h(x)和实际y的差值,不是针对x的函数。

机器学习中的损失函数很多,主要包括以下⼏种。⽤于回归的损失函数。
均⽅误差(Mean Square Error,MSE)函数,也叫平⽅损失或L2损失函数。 D指的是包含多个样本的数据集,N指的是样本数量(此例为200)。N前⾯还有常量2,是为了在求梯度的时候,抵消⼆次⽅后产⽣的系数,⽅便后续进⾏计算
[外链图片转存中…(img-DuL6ggafc83b8ebb44e1b0e6bc6bb92a1103.png)
平均绝对误差(Mean Absolute Error,MAE)函数,也叫L1损失函数。
平均偏差误差(mean bias error)函数。
⽤于分类的损失函数。:交叉熵损失(cross-entropy loss)函数。多分类SVM损失(hinge loss)函数。

  1. 通过梯度下降找到最佳参数

线性回归经常使用mse函数作为损失函数,因为存在着全局最⼩损失点
损失函数⽅程式中的x,y都可以视为常量,则L就只随着w和b⽽变 。mse函数就是一个w和b的二次函数。这个函数图像称为损失曲线,这是⼀个凸函数。凸函数的图像会流畅、连续地形成相对于y轴的全局最低点 在这里插入图片描述

梯度下降的过程就是在程序中⼀点点变化参数w和b,使L,也就是损失值,逐渐趋近最低点

程序中⽤梯度下降法通过求导来计算损失曲线在起点处的梯度。此时,梯度就是损失曲线导数的⽮量,它可以让我们了解哪个⽅向距离⽬标“更近”或“更远”。
如果求导后梯度为正值,则说明L正在随着w增⼤⽽增⼤,应该减⼩w,以得到更⼩的损失。
如果求导后梯度为负值,则说明L正在随着w增⼤⽽减⼩,应该增⼤w,以得到更⼩的损失。
此处在单个权重参数的情况下,损失相对于权重的梯度就称为导数;若考虑偏置,或存在多个权重参数时,损失相对于单个权重的梯度就称为偏导数。
在这里插入图片描述

梯度知道往哪个方向走,但是应该走多大步,这在机器学习中被称为学习速率。学习速率乘以损失曲线求导之后的微分值,就是⼀次梯度变化的步⻓(step size)。引⼊学习速率之后,⽤数学语⾔描述参数w随梯度更新的公式如下:在这里插入图片描述


笨蛋本人的再次注释:为什么w是减去梯度,因为w初值是随便选的一个,我们想要知道的是w怎么去改变时loss会逐渐变小,而如果求导后梯度为正值,则说明L正在随着w增⼤⽽增⼤,应该减⼩w,以得到更⼩的损失。如果求导后梯度为负值,则说明L正在随着w增⼤⽽减⼩,应该增⼤w,以得到更⼩的损失。由此我们得出应该往负梯度方向走(其实是废话,因为梯度为最快增长,负梯度就是最快下降),所以w加上负梯度方向,α是往这个方向走多少。

  1. 超参数调试

超参数指的是与模型无关的参数,例如迭代次数,学习速率

梯度原理复习

由于本人时不时忘记高数,再次对梯度原理记录:
我来用最直观的方式解释方向导数和梯度的关系,从一元到多元逐步展开。


第一步:回顾一元函数(热身)

对于 f(x)f(x)f(x),导数 f′(x)f'(x)f(x) 告诉你:

  • 正负:增长方向(正为右,负为左)
  • 大小:增长快慢

f(x+Δx)≈f(x)+f′(x)⋅Δxf(x + \Delta x) \approx f(x) + f'(x) \cdot \Delta xf(x+Δx)f(x)+f(x)Δx

只有一个方向可以走(左右),所以导数就是全部信息。


第二步:二元函数的困境

对于 f(x,y)f(x, y)f(x,y),站在点 (x0,y0)(x_0, y_0)(x0,y0),你可以往无穷多个方向走:

问题:哪个方向变化最快?变化率是多少?


第三步:方向导数——“沿指定方向的变化率”

定义

固定一个单位方向向量 u=(u1,u2)\mathbf{u} = (u_1, u_2)u=(u1,u2)(其中 u12+u22=1u_1^2 + u_2^2 = 1u12+u22=1),函数沿 u\mathbf{u}u 方向的变化率:

Duf=lim⁡h→0f(x+hu1,y+hu2)−f(x,y)hD_{\mathbf{u}}f = \lim_{h \to 0} \frac{f(x + hu_1, y + hu_2) - f(x, y)}{h}Duf=h0limhf(x+hu1,y+hu2)f(x,y)

计算公式(关键!)

核心工具:多元泰勒展开(一阶近似)
对于二元函数 f(x,y)f(x, y)f(x,y),在点 (x,y)(x, y)(x,y) 附近:

f(x+Δx,y+Δy)≈f(x,y)+∂f∂xΔx+∂f∂yΔyf(x + \Delta x, y + \Delta y) \approx f(x, y) + \frac{\partial f}{\partial x}\Delta x + \frac{\partial f}{\partial y}\Delta yf(x+Δx,y+Δy)f(x,y)+xfΔx+yfΔy

这里Δx=hu1\Delta x = hu_1Δx=hu1Δy=hu2\Delta y = hu_2Δy=hu2

Duf=∂f∂xu1+∂f∂yu2=∇f⋅uD_{\mathbf{u}}f = \frac{\partial f}{\partial x} u_1 + \frac{\partial f}{\partial y} u_2 = \nabla f \cdot \mathbf{u}Duf=xfu1+yfu2=fu

这就是方向导数 = 梯度与方向向量的点积
Duf=(∂f∂x,∂f∂y)⏟这就是梯度 ∇f⋅(u1,u2)⏟方向向量 u=∇f⋅u\boxed{D_{\mathbf{u}}f = \underbrace{\left(\frac{\partial f}{\partial x}, \frac{\partial f}{\partial y}\right)}_{\text{这就是梯度 } \nabla f} \cdot \underbrace{(u_1, u_2)}_{\text{方向向量 } \mathbf{u}} = \nabla f \cdot \mathbf{u}}Duf=这就是梯度 f(xf,yf)方向向量 u(u1,u2)=fu

第四步:梯度——“所有偏导数组成的向量”

∇f=(∂f∂x,∂f∂y)\nabla f = \left( \frac{\partial f}{\partial x}, \frac{\partial f}{\partial y} \right)f=(xf,yf)

梯度本身不是变化率,而是一个向量,它储存了各个坐标轴方向的变化信息。


第五步:点积揭示的几何意义

Duf=∇f⋅u=∥∇f∥⋅∥u∥⋅cos⁡θ=∥∇f∥cos⁡θD_{\mathbf{u}}f = \nabla f \cdot \mathbf{u} = \|\nabla f\| \cdot \|\mathbf{u}\| \cdot \cos\theta = \|\nabla f\| \cos\thetaDuf=fu=∥∇fucosθ=∥∇fcosθ

情况cos⁡θ\cos\thetacosθ方向导数含义
u\mathbf{u}u∇f\nabla ff 同向111∣∇f∣|\nabla f|∣∇f最大增长
u\mathbf{u}u∇f\nabla ff 反向−1-11−∣∇f∣-|\nabla f|∣∇f最大下降
u\mathbf{u}u∇f\nabla ff 垂直000000等高线方向(不变)

关键观察

  • 梯度向量 垂直于等高线(函数值不变的曲线)
  • 梯度指向 函数值增长最快的方向
  • 梯度长度 等于最大变化率

总结对比表

概念是什么作用
偏导数 ∂f∂x\frac{\partial f}{\partial x}xf标量单坐标轴方向的变化率
方向导数 DufD_{\mathbf{u}}fDuf标量任意指定方向的变化率
梯度 ∇f\nabla ff向量包含所有方向信息,指向增长最快方向

一句话记忆

梯度是"指南针"(向量,指明最陡方向),方向导数是"速度表"(标量,显示该方向的快慢)。

用点积把两者联系起来:Duf=∇f⋅uD_{\mathbf{u}}f = \nabla f \cdot \mathbf{u}Duf=fu,这就是为什么梯度方向能使方向导数最大化。


实战代码示例:

# 定义数据集

# 定义数据特征
x_data = [1, 2, 3]

# 定义数据标签
y_data = [2, 4, 6]

# 初始化参数W
w = 4

# 定义线性回归的模型(比较简单,没带b)
def forword(x):
    return x * w

# 定义损失函数
def cost(xs, ys):
    #损失函数初始值
    costvalue = 0
    for x, y in zip(xs, ys):
        y_pred = forword(x)
        costvalue += (y_pred-y)**2
    return costvalue / len(xs)

# 定义计算梯度的函数
def gradient(xs, ys):
    grad = 0
    for x, y in zip(xs, ys):
        grad += 2 * x * (x * w -y)
    return grad / len(xs)


for epoch in range(100):
    cost_val = cost(x_data, y_data)

    grad_val = gradient(x_data, y_data)

    w = w - 0.01 * grad_val


    print('训练轮次:', epoch, "w=", w, "loss", cost_val)


print("100轮后w已经训练好了,此时我们用训练好的w进行推理,学习时间为4个小时的时候最终的得分为:", forword(4))



以上是基础原理版,但是实际上直接调库线性回归函数。

常见的回归分类等算法具体sklearn基本封装好了,实现代码懒得自己手搓,调库吧就。:
两个库文档地址
https://scikitlearn.com.cn/
https://www.runoob.com/sklearn/sklearn-ml-model.html

更多推荐