机器学习笔记之线性回归的代价函数(Cost Function for Linear Regression)

前言

在监督学习中,代价函数用于衡量模型预测结果与实际观测值之间的差异或误差。其目标是使这个差异尽可能小,以便模型能够产生准确的预测。

代价函数的选择取决于所使用的算法和问题的性质。例如,在回归问题中,常见的代价函数包括均方误差(Mean Squared Error)和平均绝对误差(Mean Absolute Error)。在分类问题中,常见的代价函数包括交叉熵损失(Cross-Entropy Loss)和 Hinge 损失等。本文将以线性回归(Linear Regression)为例,对均方误差的代价函数进行代码实现,不引入损失函数(Loss Function)。

基本公式

一元线性回归

其中, w 和 b 可以称之为“参数”、“系数”或“权重”,用于绘制一条样本拟合曲线以拟合样本数据。

多元线性回归

其中, w1,w2,…,wn 和 b 可以称之为“参数”、“系数”或“权重”,用于绘制一条更复杂的样本拟合曲线以拟合不同情况下的样本数据,使拟合度更高,但也应该注意防止过拟合的情况发生。

过拟合(Overfitting)指的是模型过度拟合了训练数据中的噪声和细节,从而失去了泛化能力,无法很好地适应新的、未见过的数据。简单举例来讲,在我们拿到了一个数据集后,一个本可以用一条抛物线就可以描述趋势的函数,却用了参数更多的复杂函数以保证了每个数据对应的点都与其高度拟合,虽然在已知的数据集中达到了极高的拟合度,但却无法很好的正确预测出未来曲线的变化情况,使函数失效。

代价函数

代码实现

首先我们定义一个代价函数的函数,其次再初始化数据集,最后利用matplotlib进行绘制。

引入头文件

import numpy as np
import matplotlib.pyplot as plt

代价函数

该部分利用 numpy 实现了代价函数,numpy 在高维矩阵运算时的速度比 python 高。

# 需要 w,b 两个参数和 x,y 两个变量
def cost_function(w, b, x, y):
m = x.shape[0]

# 计算预测值
f_wb = np.dot(x, w) + b

# 计算代价函数(numpy 向量化)
cost = np.sum((f_wb - y) ** 2) / (2 * m)
return cost

初始化数据集

这一步,我们随机定义一组数据集,并定义w 和 b 的取值范围,最后计算 w[i] 和 b[i] 对应的 J(w, b) (z 轴) 的值。

# 数据集
x_train = np.array([1.0, 1.7, 2.0, 2.5, 3.0, 3.2])
y_train = np.array([250, 300, 480, 430, 630, 730, ])

# 定义 w 和 b 的取值范围
w_range = np.array([200 - 200., 200 + 200])
b_range = np.array([50 - 300., 50 + 300])
# 按照步长 100 转化成均匀分布的数值序列,作为 w 和 b 的具体取值
w_space = np.linspace(*w_range, 100)
b_space = np.linspace(*b_range, 100)

# 生成网格点坐标矩阵, 使 w 和 b 一一对应,防止出现缺失值的情况。
tmp_w, tmp_b = np.meshgrid(w_space, b_space)

# 生成一个和 b (或者 w)一样的零向量
z = np.zeros_like(tmp_b)

# 对应 w 和 b 的坐标分别计算 z 值, 即 J(w,b) 的值
for i in range(tmp_w.shape[0]):
for j in range(tmp_w.shape[1]):
z[i, j] = cost_function(tmp_w[i][j], tmp_b[i][j], x_train, y_train)
if z[i, j] == 0:
# 防止出现除以 0 的情况,所以赋值为一个非常小的数减小影响。
z[i, j] = 1e-6

绘图

# 创建三维坐标系
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# 绘制面
plt.plot_surface(tmp_b, tmp_w, z, cmap='virdis')

# 出图
plt.show()

图像结果

输出结果
输出结果

Troubleshooting

  1. 在 matplotlib 生成三维图形时,注意 z 轴只接受二维向量,否则无法正常绘制。
  2. 在进行矩阵运算时,尽量使用 numpy 库以获取最大的性能。
  3. 在生成 w 和 b 的范围时,要注意一定要使用 ‘np.meshgrid’ 方法,否则会由于部分 b 没有对应的 w 而无法计算代价函数 J(w,b)。
  4. 通常情况下,代价函数的值不会等于零,因为模型参数的取值通常会使得代价函数的值大于零。但是,由于计算精度的限制或者其他因素,可能会出现代价函数值非常接近零的情况。如果在后续计算中出现除以零的情况,就会导致错误或异常。因此,为了避免除以零的情况,可以将代价函数值为零的情况手动调整为一个非零的小值,如1e-6。这样可以保证程序在计算时不会出现除以零的错误,同时也不会显著影响到代价函数值。

参考资料

(强推|双字)2022吴恩达机器学习Deeplearning.ai课程: https://www.bilibili.com/video/BV1Pa411X76s