线性回归

什么是一个线性回归问题?

如果把线性回归模型看作一个函数,用最简单的话说,这个函数的作用就是预测。

线性回归模型的预测过程是这样的:给定一个输入特征向量,通过线性组合得到一个预测值。

举个例子:

假设有数据集:这里我们想知道工资、年龄和贷款额度之间的关系。

工资 年龄 贷款额度
1000 25 1000
2000 30 2000
3000 35 3000

我们可以用线性回归模型来预测工资,假设我们的模型是这样的: y=w1x1+w2x2

其中,y 是贷款额度,x1 是工资,x2 是年龄。

我们的目标是找到一个合适的 w1w2,使得我们的模型能够很好地预测工资。

这个函数就是一个线性函数,也就是线性回归模型。

y=w0+w1x1+w2x2=i=0nwixi

这里w0是偏置项,用来调整模型的预测值。x0是一个常数项,通常为1。

误差值

误差值是指预测值与真实值之间的差距。

  • 误差与误差之间是独立的,不会相互影响。
  • 误差的分布是正态分布,均值为0。

预测与误差:

yi=WTxi+ϵi

其中,yi 是预测值,WT 是权重向量,xi 是输入特征向量,ϵi 是误差。

误差服从正态分布:

p(ϵi)=12πσ2exp((ϵi)22σ2)

将误差代入预测值:

p(y|xi;W)=12πσ2exp((yiWTxi)22σ2)

xi;W组合之后的概率密度函数,就是我们的模型。我们希望xi;W组合之后与y越接近越好。所以希望最大化这个概率密度函数。

似然函数

似然函数为什么要使用连乘?因为前面说过,误差是独立的,所以我们可以将每个样本的概率密度函数连乘起来。

L(W)=i=1mp(y|xi;W)=i=1m12πσ2exp((yiWTxi)22σ2)

对似然函数取对数,可以将连乘转换为连加:

logL(W)=i=1mlogp(y|xi;W)=i=1mlog12πσ2exp((yiWTxi)22σ2)

展开化简:

logL(W)=m2log(2πσ2)12σ2i=1m(yWTxi)2

我们最终的目标是最大化似然函数,也就是最小化误差。前一项是常数,所以希望后一项越小越好。即:

minW12i=1m(yWTxi)2

损失函数

什么是损失函数?

损失函数也叫目标函数,是用来衡量模型预测值与真实值之间的差距的函数。

上面那个例子,我们的目标是找到一个合适的 w1w2,使得我们的模型能够很好地预测工资。损失函数可以定义为:

L(w)=12mi=1m(yiyi^)2

使用目标值和预测值之间的平方误差作为损失函数,这个损失函数叫做均方误差(Mean Squared Error,MSE)。

其中,m 是样本数量,yi 是真实值,yi^ 是预测值。

对于机器学习的大部分任务,我们都是通过最小化损失函数来优化模型的参数。

如何求解损失函数?

L(w)=12mi=1m(WTxiyi^)2=12m(XWY)T(XWY)

其中,X 是输入特征矩阵,Y 是真实值矩阵。

我们的目标是找到一个合适的 W,使得损失函数最小化。

因此,对损失函数求导,然后令导数为0,可以得到最优解。

L(W)W=1mXT(XWY)=0

解方程,得到最优解:

W=(XTX)1XTY

但是,这个方法有一个问题,就是计算量太大。当数据量很大时,计算矩阵的逆是非常耗时的。而且,矩阵的逆不一定存在。

因此,我们通常使用梯度下降法来求解损失函数的最小值。

梯度下降法

什么是梯度下降法?

梯度下降法是一种常用的优化算法,用来求解损失函数的最小值。

梯度下降法的思想是:沿着梯度的反方向,不断迭代更新参数,直到损失函数的值收敛。

目标函数

J(θ0,θ1)=12mi=1m(hθ(xi)yi)2

其中,hθ(xi)=θ0+θ1xi 是模型的预测值。

如何寻找合适的方向?

梯度下降法的核心是求解目标函数的梯度。

分别对 θ0θ1 求偏导数:

J(θ0,θ1)θ1=1mi=1m(yihθ(xi))x1i

使得梯度为0,得到最优解。因为切线方向是函数值下降最快的方向,此时梯度为0。梯度其实就是函数的导数。

注意,这里等式中的两个θj表示两个不同的θj,一个是当前的θj,一个是更新后的θj

θj=θjαJ(θj)θj=θjα1mi=1m(yihθ(xi))xji

其中,α 是学习率,用来控制参数更新的步长,xji表示第i个样本的第j个特征。

如果将所有的参数更新写成矩阵形式,可以得到:

θ=θα1mXT(XθY)

这就是梯度下降法中的批量梯度下降(Batch Gradient Descent)。但是,批量梯度下降的计算量很大,因为每次迭代都要计算所有样本的梯度。

随机梯度下降

随机梯度下降(Stochastic Gradient Descent,SGD)是梯度下降法的一种变种,它每次迭代只使用一个样本来更新参数。

θ=θα(hθ(xi)yi)xi

其中,xi 是第i个样本的特征向量,yi 是第i个样本的真实值。

随机梯度下降的优点是计算速度快,但缺点是收敛速度慢,因为每次迭代的方向不一定是最优的。

小批量梯度下降

小批量梯度下降(Mini-batch Gradient Descent)是批量梯度下降和随机梯度下降的折中方案,每次迭代使用一小部分样本来更新参数。

θ=θα1mi=1m(hθ(xi)yi)xi

其中,m 是小批量的大小。batch size的选择对模型的训练速度有很大影响。当batch size较小时,模型的训练速度较慢;当batch size较大时,模型的训练速度较快。

代码实现

给一个代码实现:

对应上面的公式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def train(self, learning_rate=0.01, num_iterations=10):
"""
使用梯度下降法训练线性回归模型
"""
cost_history = []
for _ in range(num_iterations):
self.theta = self.predict_step(learning_rate)
cost_history.append(self.compute_cost())
logger.info("第{}次迭代,损失值为{}".format(_, cost_history[-1]))

# 返回训练后的参数和损失值
return self.theta, cost_history

def predict_step(self, learning_rate):
"""
每一步迭代计算梯度并更新参数
"""
num_examples = self.data.shape[0]
# 计算预测值
prediction = self.hypothesis(self.data, self.theta)
# 计算误差
error = prediction - self.labels
# 计算梯度并更新参数
theta = self.theta - learning_rate * (1 / num_examples) * np.dot(self.data.T, error)
return theta

@staticmethod
def hypothesis(data, theta):
"""
计算预测值
"""
return np.dot(data, theta)

def compute_cost(self):
"""
计算损失, 这里使用均方误差
"""
num_examples = self.data.shape[0]
prediction = self.hypothesis(self.data, self.theta)
error = prediction - self.labels
cost = (1 / (2 * num_examples)) * np.dot(error.T, error)
return cost

参考代码:线性回归的从零开始实现