前言:开始学习吴恩达教授的机器学习课程,记录并实现其中的算法。在实现过程中,还未理解如何准确的找到α这个值的取值。
一元线性回归其实就是从一堆训练集中去算出一条直线,使数据集到直线之间的距离差最小。举个例子,唯一特征X(工龄),共有m = 50个数据数量,Y(薪水)是实际结果,要从中找到一条直线,使数据集到直线之间的距离差最小,如下图所示:
这里的薪水数据为手动自定义的,导致了误差较大…
线性回归所提供的思路就是:
可以将特征X中每一个值xi都带入其中,得到对应的 h_θ(xi),可以将损失J(θ)定义为yi和hg(xi)之间的差值平方的和:
接着求出 min( θ_0, θ_1) J( θ_0, θ_1)的值。
将梯度下降应用到最小化平方差代价函数中,得出期望的J(θ_0, θ_1)。如下图所示:
其中最为关键的为梯度下降算法中的导数项,可以对其进行简化,如下所示:
通过对导数项的计算,就可以按照梯度下降的公式同步跟新θ_0, θ_1的值。
公式里的 α,表示学习速率,控制以多大幅度更新参数θj。
import numpy as np
import matplotlib.pyplot as plt
### 载入数据----画出图像
# 导入数据
data = np.genfromtxt('data_1.csv', delimiter=',')
#data = np.genfromtxt('data.csv', delimiter=',')
# print(data) 列表
x_data = data[:, 0]
y_data = data[:, 1]
# 画图
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.title("工龄 与 薪水 散点图")
plt.xlabel("X 工龄")
plt.ylabel("Y 薪水(元)")
plt.scatter(x_data,y_data)
plt.show()
# 学习率 learning_rate
#lr = 0.0001
#lr = 0.003
lr = 0.35
# 截距 θ_0
theta_0 = 0
# 斜率 θ_1
theta_1 = 0
# 最大迭代次数
#iterations = 1000
iterations = 50
###### 求解拟合此数据的直线参数
# 将梯度下降法应用到最小化平方差代价函数
## 线性回归
# 线性假设 h_θ(x) = θ_0 + θ_1 * x
# 平方差代价函数 J(θ) = 循环{ (h_θ(x^(i) - y^(i))** 2 } / 2m 其中 m为循环次数
## 梯度下降
# θ_j = θ_j - α {J(θ_0, θ_1)的偏导}
# 什么叫做损失函数?其实就是计算一个模型与各个点之间的差距到底有多大!!如果差距大,说明我们所选择的模型比较差,如果差距很小,说明这个模型不错。
# 平方差代价函数,求J(θ)
def compute_error(theta_0, theta_1, x_data, y_data):
totalError = 0 # 即J(θ)
for i in range(0,len(x_data)):
# 预测值 - 实际值
totalError += ( theta_0 + theta_1 * x_data[i] - y_data[i] ) ** 2
return totalError / float(len(x_data)) / 2.0 # 即得出 J(θ)
# 梯度下降---算法思路
# 开始时 theta_0 和 theta_1通常 设置为0
# 持续改变 theta_0 和 theta_1 去减少 J(theta_0 ,theta_1),
# 直到出现我们期望的结果出现
def gradient_descent(theta_0, theta_1, x_data, y_data, lr,iterations):
# 数据集的总量 m
m = float(len(x_data))
# 循环 迭代次数 iteartions
for i in range(iterations):
theta_0_grad = 0
theta_1_grad = 0
# 计算总和,再求平均 即==> 求梯度下降式子中的 导数项
for j in range(0, len(x_data)):
theta_0_grad += (1/m) * (theta_0 + theta_1 * x_data[j] - y_data[j] )
theta_1_grad += (1/m) * (theta_0 + theta_1 * x_data[j] - y_data[j] ) * x_data[j]
# 同步更新 theta_0 和 theta_1 梯度下降
theta_0 = theta_0 - lr * theta_0_grad
theta_1 = theta_1 - lr * theta_1_grad
# 每迭代2次,输出一次图像
if i % 5 == 0:
print("当前迭代次数:",i + 1)
plt.plot(x_data, y_data, 'b.')
plt.plot(x_data, theta_0 + theta_1 * x_data, 'r')
plt.title("工龄 与 薪水 散点图")
plt.xlabel("工龄")
plt.ylabel("薪水(元)")
plt.show()
# print中的字符串里面的 {0} 相当于索引,所取值对应于 format括号里的每个值的顺序
print(" theta_0 = {0}, theta_1 = {1}, 误差 = {2}".format(theta_0, theta_1,compute_error(theta_0, theta_1, x_data,y_data)))
return theta_0, theta_1
# 开始运行
print("Running...")
# 执行 梯度下降
theta_0, theta_1 = gradient_descent(theta_0, theta_1, x_data, y_data, lr, iterations)
# 输出最终的值
print("final ==> theta_0 = {0}, theta_1 = {1}, 误差 = {2}".format(theta_0, theta_1, compute_error(theta_0, theta_1, x_data, y_data)))