faithful_x = faithful_X.ravel().astype(float)
faithful_y = faithful_y.astype(float)
# The objective is defined on the complete, fixed dataset.
def linear_mse(theta_0, theta_1):
predictions = theta_0 + theta_1 * faithful_x
return np.mean((predictions - faithful_y) ** 2)
# Exact least-squares minimizer for the complete dataset.
full_data_model = LinearRegression().fit(faithful_X, faithful_y)
theta_star = np.array([
full_data_model.intercept_,
full_data_model.coef_[0],
])
# An illustrative sequence of parameter choices ending at the minimizer.
theta_path = np.array([
(0.0, 0.0),
(10.0, 2.0),
(20.0, 4.0),
(30.0, 7.0),
theta_star,
])
path_costs = np.array([
linear_mse(theta_0, theta_1)
for theta_0, theta_1 in theta_path
])
# Evaluate the same objective throughout parameter space.
theta_0_values = np.linspace(0, 100, 200)
theta_1_values = np.linspace(0, 20, 200)
theta_0_grid, theta_1_grid = np.meshgrid(theta_0_values, theta_1_values)
cost_grid = np.empty_like(theta_0_grid, dtype=float)
for row in range(theta_0_grid.shape[0]):
for column in range(theta_0_grid.shape[1]):
cost_grid[row, column] = linear_mse(
theta_0_grid[row, column],
theta_1_grid[row, column],
)
# Left: selected hypotheses. Right: their objective values in parameter space.
fig = plt.figure(figsize=(12, 4.8))
ax1 = fig.add_subplot(1, 2, 1)
input_order = np.argsort(faithful_x)
ax1.scatter(faithful_x, faithful_y, s=18, alpha=0.75, label="data")
ax1.axhline(faithful_y.mean(), color="gray", ls="--", lw=1, label=r"$\bar y$")
for index, (theta_0, theta_1) in enumerate(theta_path):
hypothesis_values = theta_0 + theta_1 * faithful_x
ax1.plot(
faithful_x[input_order], hypothesis_values[input_order],
lw=2 if index == len(theta_path) - 1 else 1.2,
alpha=1.0 if index == len(theta_path) - 1 else 0.85,
label=fr"$\theta_0={theta_0:.3f},\ \theta_1={theta_1:.3f}$",
)
ax1.set_xlabel("Eruption duration (min)")
ax1.set_ylabel("Waiting time to next eruption (min)")
ax1.set_title("Selected hypotheses in input-output space")
ax1.legend(fontsize=8, loc="best")
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
vmin = np.percentile(cost_grid, 5)
vmax = np.percentile(cost_grid, 95)
surf = ax2.plot_surface(
theta_0_grid, theta_1_grid, cost_grid, rstride=3, cstride=3,
cmap="viridis", linewidth=0, antialiased=False,
vmin=vmin, vmax=vmax, alpha=0.6,
)
ax2.plot(
theta_path[:, 0], theta_path[:, 1], path_costs,
color='crimson', marker='o', lw=2,
label="illustrative sequence",
)
ax2.set_xlabel(r'$\theta_0$')
ax2.set_ylabel(r'$\theta_1$')
ax2.set_zlabel(r'$J(\theta)$ (MSE)')
ax2.set_title(r"Objective over parameter space")
ax2.legend(loc="best", fontsize=8)
ax2.view_init(elev=30, azim=-60)
fig.colorbar(surf, ax=ax2, shrink=0.7, pad=0.05, label="MSE")
plt.tight_layout()
plt.show()