机器学习笔记03线性回归
机器学习笔记03线性回归
如果只包括⼀个⾃变量(特征x)和⼀个因变量(标签y),且两者的关系可⽤⼀条直线近似表示,这种回归分析就称为⼀元线性回归分析。如果回归分析中包括两个或两个以上的⾃变量,且因变量和⾃变量之间是线性关系,则称为多元线性回归分析。
机器学习步骤:
- 问题定义
- 数据的收集和预处理 (读取,可视化,相关分析,散点图,数据集清洗和规范化,拆分数据集为训练集和测试集,数据归一化)
相关分析⽤⼏⾏代码即可实现,并可以⽤热⼒图(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%。
- 选择机器学习模型(什么模型,什么参数)
假设函数:到最佳的函数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)函数。
- 通过梯度下降找到最佳参数
线性回归经常使用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加上负梯度方向,α是往这个方向走多少。
- 超参数调试
超参数指的是与模型无关的参数,例如迭代次数,学习速率
梯度原理复习
由于本人时不时忘记高数,再次对梯度原理记录:
我来用最直观的方式解释方向导数和梯度的关系,从一元到多元逐步展开。
第一步:回顾一元函数(热身)
对于 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=limh→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=h→0limhf(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)+∂x∂fΔx+∂y∂fΔ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=∂x∂fu1+∂y∂fu2=∇f⋅u
这就是方向导数 = 梯度与方向向量的点积
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(∂x∂f,∂y∂f)⋅方向向量 u(u1,u2)=∇f⋅u
第四步:梯度——“所有偏导数组成的向量”
∇f=(∂f∂x,∂f∂y)\nabla f = \left( \frac{\partial f}{\partial x}, \frac{\partial f}{\partial y} \right)∇f=(∂x∂f,∂y∂f)
梯度本身不是变化率,而是一个向量,它储存了各个坐标轴方向的变化信息。
第五步:点积揭示的几何意义
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=∇f⋅u=∥∇f∥⋅∥u∥⋅cosθ=∥∇f∥cosθ
| 情况 | cosθ\cos\thetacosθ | 方向导数 | 含义 |
|---|---|---|---|
| u\mathbf{u}u 与 ∇f\nabla f∇f 同向 | 111 | ∣∇f∣|\nabla f|∣∇f∣ | 最大增长 |
| u\mathbf{u}u 与 ∇f\nabla f∇f 反向 | −1-1−1 | −∣∇f∣-|\nabla f|−∣∇f∣ | 最大下降 |
| u\mathbf{u}u 与 ∇f\nabla f∇f 垂直 | 000 | 000 | 等高线方向(不变) |
关键观察:
- 梯度向量 垂直于等高线(函数值不变的曲线)
- 梯度指向 函数值增长最快的方向
- 梯度长度 等于最大变化率
总结对比表
| 概念 | 是什么 | 作用 |
|---|---|---|
| 偏导数 ∂f∂x\frac{\partial f}{\partial x}∂x∂f | 标量 | 单坐标轴方向的变化率 |
| 方向导数 DufD_{\mathbf{u}}fDuf | 标量 | 任意指定方向的变化率 |
| 梯度 ∇f\nabla f∇f | 向量 | 包含所有方向信息,指向增长最快方向 |
一句话记忆
梯度是"指南针"(向量,指明最陡方向),方向导数是"速度表"(标量,显示该方向的快慢)。
用点积把两者联系起来:Duf=∇f⋅uD_{\mathbf{u}}f = \nabla f \cdot \mathbf{u}Duf=∇f⋅u,这就是为什么梯度方向能使方向导数最大化。
实战代码示例:
# 定义数据集
# 定义数据特征
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
更多推荐



所有评论(0)