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
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() |