You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
3.3 KiB

import numpy as np
import matplotlib.pyplot as plt
# 设置中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 生成数据集
def gen():
m = 20
X0 = np.ones((m, 1))
X1 = np.arange(1, m+1).reshape(m, 1)
X = np.hstack((X0, X1))
true_params = np.array([[1], [1.5]])
y = np.dot(X, true_params) + np.random.normal(0, 2, size=(m, 1))
return X, X1, y, m
# 定义代价函数 (均方误差)
def cos(theta, X, y, m):
error = np.dot(X, theta) - y
return (1 / (2 * m)) * np.dot(error.T, error)[0, 0]
# 定义梯度函数
def gra(theta, X, y, m):
error = np.dot(X, theta) - y
return (1 / m) * np.dot(X.T, error)
# 梯度下降迭代
def des(X, y, m, al=0.01, max=10000, t=1e-5):
"""
使用梯度下降算法求解最优参数
参数:
X: 特征矩阵
y: 目标值向量
m: 样本数量
al: 学习率
max: 最大迭代次数
t: 收敛阈值
返回:
theta: 最优参数
costs: 每次迭代的代价函数值
"""
theta = np.array([[1], [1]]) # 初始化参数 [b, w]
costs = [] # 记录每次迭代的代价函数值
for iteration in range(max):
gradient = gra(theta, X, y, m)
theta = theta - al * gradient
cost = cos(theta, X, y, m)
costs.append(cost)
# 检查收敛条件
if np.max(np.abs(gradient)) < t:
print(f"在第 {iteration+1} 次迭代后收敛")
break
# 每100次迭代打印一次信息
if (iteration + 1) % 100 == 0:
print(f"迭代 {iteration+1}/{max}, 代价: {cost:.6f}")
return theta, costs
# 绘制结果
def res(X1, y, theta, costs=None):
plt.figure(figsize=(14, 5))
# 绘制数据点和拟合直线
plt.subplot(1, 2, 1)
plt.scatter(X1, y, s=30, c="red", marker="s", label="数据点")
plt.xlabel("X")
plt.ylabel("Y")
plt.title("数据点与拟合直线")
x_range = np.arange(0, 21, 0.2)
y_pred = theta[0] + theta[1] * x_range
plt.plot(x_range, y_pred, 'b-', label=f'拟合直线: y = {theta[0][0]:.4f} + {theta[1][0]:.4f}x')
plt.legend()
# 如果提供了代价函数值,绘制代价函数变化曲线
if costs is not None:
plt.subplot(1, 2, 2)
plt.plot(range(1, len(costs) + 1), costs, 'g-')
plt.xlabel("迭代次数")
plt.ylabel("代价函数值")
plt.title("代价函数收敛过程")
plt.grid(True)
plt.tight_layout()
plt.show()
# 主函数
def main():
# 生成数据集
X, X1, y, m = gen()
# 设置超参数
al = 0.01 # 学习率
max = 10000 # 最大迭代次数
t = 1e-5 # 收敛阈值
# 执行梯度下降
print("开始执行梯度下降算法...")
theta, costs = des(X, y, m, al, max, t)
# 输出结果
print("\n优化结果:")
print(f"截距项 b = {theta[0][0]:.6f}")
print(f"斜率项 w = {theta[1][0]:.6f}")
print(f"最终代价函数值 = {cos(theta, X, y, m):.6f}")
# 绘制结果
res(X1, y, theta, costs)
if __name__ == "__main__":
main()