代码如下:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.patches import Patch
# 生成二维输入数据
np.random.seed(0)
X1 = 2 * np.random.rand(100, 1) # 第一个特征
X2 = 3 * np.random.rand(100, 1) # 第二个特征
X = np.hstack((X1, X2)) # 将两个特征合并为二维输入
# 生成目标值 y(线性关系 + 噪声)
y = 4 + 3 * X1 + 5 * X2 + np.random.randn(100, 1)
# 添加偏置项(全为1的列)
X_b = np.c_[np.ones((100, 1)), X]
# 初始化参数 theta (theta0, theta1, theta2)
theta = np.random.randn(3, 1)
# 学习率
eta = 0.1
# 迭代次数
n_iterations = 100
# 用于存储每次迭代的损失值
loss_history = []
# 用于存储每次迭代的 theta 值
theta_history = [theta]
# 梯度下降
for iteration in range(n_iterations):
gradients = 2 / 100 * X_b.T.dot(X_b.dot(theta) - y) # 计算梯度
theta = theta - eta * gradients # 更新参数
theta_history.append(theta)
# 计算损失(均方误差)
loss = np.mean((X_b.dot(theta) - y) ** 2)
loss_history.append(loss)
# 可视化每次拟合的平面
def plot_fitted_plane(X1, X2, y, theta, iteration):
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111, projection='3d')
scatter = ax.scatter(X1, X2, y, color='blue', label='Data points') # 绘制数据点
# 生成网格点用于绘制平面
X1_grid, X2_grid = np.meshgrid(np.linspace(X1.min(), X1.max(), 10), np.linspace(X2.min(), X2.max(), 10))
y_grid = theta[0] + theta[1] * X1_grid + theta[2] * X2_grid # 计算平面
surface = ax.plot_surface(X1_grid, X2_grid, y_grid, alpha=0.5, facecolor='red') # 绘制平面
# 手动创建图例
legend_elements = [
Patch(facecolor='blue', label='Data points'),
Patch(facecolor='red', label=f'Fitted plane (Iteration {iteration})')
]
ax.legend(handles=legend_elements)
ax.set_xlabel('X1')
ax.set_ylabel('X2')
ax.set_zlabel('y')
ax.set_title(f'Linear Regression with Gradient Descent (Iteration {iteration})')
plt.show()
# 每隔 20 次迭代绘制一次拟合平面
for i in range(0, n_iterations, 20):
plot_fitted_plane(X1, X2, y, theta_history[i].flatten(), i)
# 绘制损失函数的变化
plt.figure(figsize=(10, 6))
plt.plot(range(n_iterations), loss_history, color='red')
plt.xlabel('Iterations')
plt.ylabel('Loss')
plt.title('Loss Function over Iterations')
plt.show()
输入 X 为2维度 , XY 一共三维, 所以可以可视化在一个 3d 图形中。
X1 = 2 * np.random.rand(100, 1) # 第一个特征
X2 = 3 * np.random.rand(100, 1) # 第二个特征
X = np.hstack((X1, X2)) # 将两个特征合并为二维输入
# 生成目标值 y(线性关系 + 噪声)
y = 4 + 3 * X1 + 5 * X2 + np.random.randn(100, 1)
这是随机生成 x1 和x2 , 然后 根据 y = 4 + 3*x1 + 5*x2 + 随机噪音来生成 y
最后会拟合为一个平面。 为啥会这样?
可以理解为 起点 和 两个垂直方向的向量 可以 张开一个 平面。
也可以理解为 ,
-
如果方程中只有一个自变量(例如
y = 4 + 3 * X1
),那么它是一条 直线。 -
如果有两个自变量(例如
y = 4 + 3 * X1 + 5 * X2
),那么它是一个 平面。 -
如果有更多自变量(例如
y = 4 + 3 * X1 + 5 * X2 + 2 * X3
),那么它是一个 超平面(在更高维空间中)。
梯度下降: