梯度下降与代价函数解析(代码演示,带解析)
·
"""
梯度下降与代价函数 —— 纯代码解析
以房价预测(线性回归)为例
"""
import numpy as np
import matplotlib.pyplot as plt
# ========================================
# 1. 准备数据
# ========================================
# 特征:面积 (平方英尺)
X = np.array([1500, 2000, 1200, 1800, 2500])
# 标签:房价 (美元)
y = np.array([300000, 450000, 250000, 380000, 550000])
m = len(y) # 样本数量
print(f"样本数量: {m}")
print(f"面积范围: {X.min()} - {X.max()}")
print(f"房价范围: {y.min()} - {y.max()}\n")
# ========================================
# 2. 特征缩放(标准化)
# ========================================
# 原因:面积是上千的数值,如果不缩放,梯度下降会跑得很慢
X_mean = np.mean(X)
X_std = np.std(X)
X_scaled = (X - X_mean) / X_std # 标准化公式: (x - μ) / σ
print(f"面积 - 均值: {X_mean:.2f}, 标准差: {X_std:.2f}")
print(f"缩放后面积范围: {X_scaled.min():.2f} - {X_scaled.max():.2f}\n")
# ========================================
# 3. 代价函数(Cost Function)
# ========================================
def compute_cost(X, y, w, b):
"""
计算均方误差的一半(代价函数)
参数:
X: 特征数据(标准化后)
y: 真实标签
w: 权重(斜率)
b: 偏置(截距)
返回:
cost: 代价函数值(越小代表预测越准)
"""
m = len(y)
# 预测值 = 权重 × 特征 + 偏置
predictions = w * X + b
# 误差 = 预测值 - 真实值
errors = predictions - y
# 平方误差求和,取平均,再除以2(方便后面求导)
cost = (1 / (2 * m)) * np.sum(errors ** 2)
return cost
# ========================================
# 4. 计算梯度(Gradient)
# ========================================
def compute_gradient(X, y, w, b):
"""
计算代价函数对 w 和 b 的偏导数(梯度)
梯度告诉我们应该往哪个方向、走多远来调整参数
参数:
X, y, w, b: 同代价函数
返回:
dw: 权重 w 的梯度
db: 偏置 b 的梯度
"""
m = len(y)
# 预测值
predictions = w * X + b
# 误差
errors = predictions - y
# dw:所有误差乘以各自特征值的累加,再取平均
dw = (1 / m) * np.sum(errors * X)
# db:所有误差的累加,再取平均
db = (1 / m) * np.sum(errors)
return dw, db
# ========================================
# 5. 梯度下降(Gradient Descent)
# ========================================
def gradient_descent(X, y, w_init, b_init, learning_rate, num_iterations):
"""
梯度下降算法:反复用梯度来更新 w 和 b,让代价越来越小
参数:
X, y: 数据
w_init, b_init: w 和 b 的初始值(通常从0开始)
learning_rate: 学习率(每一步迈多大)
num_iterations: 迭代次数(跑多少步)
返回:
w, b: 优化后的参数
cost_history: 每次迭代的代价(用来画下降曲线)
"""
w = w_init
b = b_init
cost_history = [] # 记录每一步的代价
for i in range(num_iterations):
# 1. 先算出当前的梯度(方向和步长)
dw, db = compute_gradient(X, y, w, b)
# 2. 往梯度的反方向走一小步(因为梯度指向上升,我们要下降)
w = w - learning_rate * dw
b = b - learning_rate * db
# 3. 记录这一步的代价,方便后面看下降曲线
cost = compute_cost(X, y, w, b)
cost_history.append(cost)
# 每100步打印一次进度
if i % 200 == 0:
print(f"迭代 {i:4d}: cost = {cost:.2f}, w = {w:.4f}, b = {b:.2f}")
return w, b, cost_history
# ========================================
# 6. 开始训练
# ========================================
print("开始训练...")
print("-" * 50)
# 初始化参数:w 和 b 都从 0 开始
w_init = 0
b_init = 0
# 超参数
learning_rate = 0.1 # 学习率:步子太大容易跑过头,太小跑得太慢
num_iterations = 1000 # 迭代次数
# 执行梯度下降
w_final, b_final, cost_history = gradient_descent(
X_scaled, y, w_init, b_init, learning_rate, num_iterations
)
print("-" * 50)
print(f"\n最终结果: w = {w_final:.4f}, b = {b_final:.2f}")
print(f"最终代价: {cost_history[-1]:.2f}")
print(f"代价下降倍数: {cost_history[0] / cost_history[-1]:.0f} 倍\n")
# ========================================
# 7. 可视化代价下降曲线
# ========================================
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 左图:代价下降曲线
axes[0].plot(range(len(cost_history)), cost_history, 'b-', linewidth=2)
axes[0].set_xlabel('迭代次数', fontsize=12)
axes[0].set_ylabel('代价函数值', fontsize=12)
axes[0].set_title('梯度下降:代价随迭代的变化', fontsize=14)
axes[0].grid(True, linestyle='--', alpha=0.6)
# 右图:拟合直线 vs 原始数据
# 把缩放后的特征还原,方便画图
X_plot = np.linspace(X.min(), X.max(), 100)
X_plot_scaled = (X_plot - X_mean) / X_std
y_plot = w_final * X_plot_scaled + b_final
axes[1].scatter(X, y, color='red', s=80, label='真实数据', zorder=5)
axes[1].plot(X_plot, y_plot, 'b-', linewidth=2, label='拟合直线')
axes[1].set_xlabel('面积 (平方英尺)', fontsize=12)
axes[1].set_ylabel('房价 (美元)', fontsize=12)
axes[1].set_title('线性回归:找到最佳直线', fontsize=14)
axes[1].legend()
axes[1].grid(True, linestyle='--', alpha=0.6)
plt.tight_layout()
plt.show()
# ========================================
# 8. 预测新房价
# ========================================
print("\n预测新房价:")
new_areas = np.array([1600, 2200, 3000])
for area in new_areas:
# 记住:预测前要先做同样的标准化
area_scaled = (area - X_mean) / X_std
price_pred = w_final * area_scaled + b_final
print(f"面积 {area:4d} 平方英尺 → 预测房价 ${price_pred:,.0f}")
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)