理论
回归问题通常用于连续值的预测,可以总结为给定x, 想办法得到f(x),使得f(x)的值尽可能逼近对应x的真实值y。
假设,输入变量x与输出值y成线性关系,比如随着年龄(x)增大, 患癌症的概率(y)也会逐渐增大。
则有,
f(x) = w * x b
其中:x为输入值,f(x)为预测值,w为权重,b为修正的常量
我们给定w,b一个初始值。最终的目标是得到一个w, b的确定值,使得f(x)与真实值y的误差尽可能小。
于是,定义一个用来评价预测值与真实值之间的误差的函数loss:
loss = ∑_i (w * x_i b - y_i)
我们认为当这个损失函数最小的时候能够得到不错的w和b,从而获得不错的估计值。因此,问题就转换成了找到loss的最小值。
为了找到最小值,这里使用梯度下降法(Gradient Descent)。
梯度下降算法的核心就是一个函数的导数是指向函数值的增长方向的。因此当导数值变化的时候,我们就可以得到函数的极小值。为了找到最小值,这个计算导数的最小值得方向应该是朝着导数变小的方向来前进。
为了避免单次变化太大,一步跨过最小点,我们需要使用学习率(leaning rate)乘以导数,这个就是步长,这样就可以防止跨过最小点。
总结,目标是得到w’和b’,为了得到这两个值我们使用了一个损失函数,损失函数最小的时候的可以得到最优的w’和b’,为了得到最小的损失函数我们使用梯度下降方法。
- 构造损失函数
- 梯度下降找到最小的损失函数
就这么简单。
代码演示
这里单纯使用数学方式,借助python numpy来实现。(过程仅供参考,不一定写的标准)
原始数据为csv文件。
代码语言:python代码运行次数:0复制import numpy as np
from matplotlib import pyplot as plt
def loss_function(b: float, w: float, points: np.ndarray):
totalError = 0
loss_b = 0
loss_w = 0
for i in range(0, len(points)):
x = points[i, 0]
y = points[i, 1]
totalError = (y - (x*w b))**2
loss_b = 2 * (1 / len(points)) * ((x*w b) - y)
loss_w = 2 * (1 / len(points)) * ((x*w b) - y) * x
totalError = totalError / len(points)
return loss_b, loss_w, totalError
def gradient_descent_iterator(num_iterations: int, initial_b: float, initial_w: float, points: np.ndarray, leaning_rate: float):
b = initial_b
w = initial_w
totalError = 0
for i in range(num_iterations):
[b, w, totalError] = gradient_descent_step(b, w, points, leaning_rate)
print("step{0}====b:{1}, w:{2}, loss: {3}".format(str(i), str(b), str(w), str(totalError)))
return [b, w, totalError]
def gradient_descent_step(b: float, w: float, points: np.ndarray, leaning_rate: float):
loss_b, loss_w, totalError = loss_function(b, w, points)
new_b = b - leaning_rate * loss_b
new_w = w - leaning_rate * loss_w
return [new_b, new_w, totalError]
def draw_figure(points: np.ndarray, b: float, w: float):
xPoints = points.transpose()[0]
yPoints = points.transpose()[1]
yPredict = xPoints * w b
plt.scatter(xPoints, yPoints)
plt.plot(xPoints, yPredict)
plt.legend(['yPoints', 'yPredict'])
plt.show()
def run():
# 将csv文件内的数据读入并转成shape为(100, 2)的ndarray
points = np.genfromtxt('data.csv', delimiter=',')
# 学习率
leaning_rate = 0.0001
# 修正常量初始值
initial_b = 0
# 权重初始值
initial_w = 0
# 迭代次数
num_iterations = 1000
draw_figure(points, initial_b, initial_w)
[b, w, totalError] = gradient_descent_iterator(num_iterations, initial_b, initial_w, points, leaning_rate)
draw_figure(points, b, w)
if '__main__' == __name__:
run()
结果打印如下:
可以看到,虽然我们设置迭代1000次,但由于过于简单,在迭代第8次的时候,损失就已经由5565降到了112,并趋于平缓。
训练前和训练后的图像绘制如下:
拟合的结果还是比较符合预期的。