In this exercise you will implement a method to estimate the model parameters of single variate (single input) 2-nd and 3-rd order polynomials and use these models to predict a label for new datapoints. Next week you will extend this method to $n$-th order, single variate, polynomials in a fairly straightforward manner.
A 2nd-order polynomial model, also known as a quadratic model, can be expressed as:
$$ y = w_0 + w_1 x + w_2 x^2 $$This model assumes that the relationship between the input $x$ and the label $y$ is non-linear and quadratic. This way a curved relationship can be modelled which can capture patterns that a simple linear model might miss.
By fitting this model, the aim is to find the parameters $w_0$, $w_1$, and $w_2$ that minimize the difference between the predicted values and the actual data, providing a more flexible fit compared to a linear model.
Run the cell below to load libraries and construct the datasets:
import numpy as np
import matplotlib.pyplot as plt
quadratic_dataset_1 = np.array([[1, 2],
[2, 3],
[3, 6]])
quadratic_dataset_2 = np.array([[9, 3],
[7, 5],
[1, 9]])
quadratic_dataset_3 = np.array([[8, 4],
[10, 5],
[3, 1]])
Throughout the next tasks, the aim is to construct the design matrix using the known variables, followed by learning the model parameters (solving) using the inverse of the design matrix. The subsequent tasks involve using the learnt model parameters to predict new unseen inputs and plotting the results.
separate_inputs_labels
function below. The function takes a dataset as input and returns the inputs as the X_quadratic
matrix and the labels as the y_quadratic
vector.def separate_inputs_labels(dataset):
"""
This function takes a dataset as input and returns the inputs and labels.
Parameters:
dataset (numpy array): The dataset to be separated.
Returns:
X_quadratic (3x1 numpy array): The input matrix.
y_quadratic (1x3 numpy array): The labels vector.
"""
...
return X_quadratic, y_quadratic
# Applying the function to each quadratic dataset
X1_quadratic, y1_quadratic = separate_inputs_labels(quadratic_dataset_1)
X2_quadratic, y2_quadratic = separate_inputs_labels(quadratic_dataset_2)
X3_quadratic, y3_quadratic = separate_inputs_labels(quadratic_dataset_3)
print("X1_quadratic: \n", X1_quadratic)
print("y1_quadratic: \n", y1_quadratic)
X1_quadratic: [[1] [2] [3]] y1_quadratic: [2 3 6]
Reuse the code from the in-class exercise:
print("Design Matrix for Dataset 1:\n", X1_quadratic_design)
Design Matrix for Dataset 1: [[1. 1. 1.] [4. 2. 1.] [9. 3. 1.]]
weigths
in the cells below), then print the results.print("Model parameters for Model 1:", weights1_quadratic)
Model parameters for Model 1: [ 1. -2. 3.]
plot_quadratic_model
function to plot the results.# Function to plot data points and fitted quadratic model
def plot_quadratic_model(X, y, weights):
# Plot the data points
plt.scatter(X, y, color='blue', label='Given Points')
# Extend x_vals range to include zero for correct visualization
x_vals = np.linspace(0, max(X) + 1, 100)
y_vals = weights[0] * x_vals**2 + weights[1] * x_vals + weights[2]
# Plot the fitted polynomial
plt.plot(x_vals,
y_vals,
color='red',
label=f'Poly: y = {weights[0]:.2f}x^2 + {weights[1]:.2f}x + {weights[2]:.2f}')
# Plot the y-intercept
plt.scatter(0, weights[2], color='green', zorder=5, label=f'Y-intercept (0, {weights[2]:.2f})')
# Add title and labels
plt.title('Quadratic Model')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
plot_quadratic_model(X1_quadratic, y1_quadratic, weights1_quadratic)
To make predictions with a polynomial model, you apply the polynomial equation to the new input using the estimated model parameters. The model then calculates the predicted output based on the learned relationship between the variables.
The cell below contains an array of new inputs. Follow these steps to predict a label for the new input:
plot_quadratic_model_with_predictions
function. new_inputs
array with the points 1.5
and -1
. Follow the same steps as above to obtain labels for each input. # New array of inputs for prediction, currently containing a single element
new_input = np.array([14])
def plot_quadratic_model_with_predictions(X, y, weights, new_input, predicted_labels):
# Plot the original data points
plt.scatter(X, y, color='blue', label='Given Points')
# Plot the fitted quadratic model
x_vals = np.linspace(min(X.min(), new_input.min()), max(X.max(), new_input.max()), 100)
y_vals = weights[0] * x_vals**2 + weights[1] * x_vals + weights[2]
plt.plot(
x_vals,
y_vals,
color='red',
label=(
f'Poly: y = {weights[0]:.2f}x^2 + {weights[1]:.2f}x + '
f'{weights[2]:.2f}'
))
# Plot the new inputs and their predicted labels
plt.scatter(new_input, predicted_labels, color='orange', label='Predicted Points')
# Add title, labels, and legend
plt.title('Quadratic Model with Predictions')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
This exercise is about third order polynomials which offer an increased flexibility in modelling data compared to 1. and 2. order polynomials by introducing a cubic term $x^3$.
A 3rd-order polynomial model is given by
$$ y = w_0 + w_1 x + w_2 x^2 + w_3 x^3 $$In the next tasks you will follow similar steps as 1. and 2. order polynomial. This includes preparing the dataset, constructing the design matrix, calculating the model weights, plotting the results, and using the model to make predictions for new inputs.
Run the cell below to construct a new dataset:
cubic_dataset = np.array([[7, 6], [5, 24], [8, 60], [1, 120]])
X_cubic
that contain the inputs, and a vector called y_cubic
containing the corresponding labels.# Write your solution here
plot_cubic_model
function to plot the results.# Function to plot data points and fitted cubic model
def plot_cubic_model(X, y, weights):
# Plot the data points
plt.scatter(X, y, color='blue', label='Given Points')
# Extend x_vals range to include zero for correct visualization
x_vals = np.linspace(0, max(X) + 1, 100)
y_vals = weights[0] * x_vals**3 + weights[1] * x_vals**2 + weights[2] * x_vals + weights[3]
# Plot the fitted polynomial
plt.plot(
x_vals,
y_vals,
color='red',
label=(
f'Poly: y = {weights[0]:.2f}x^3 + {weights[1]:.2f}x^2 + '
f'{weights[2]:.2f}x + {weights[3]:.2f}'
))
# Plot the y-intercept
plt.scatter(0, weights[3], color='green', zorder=5, label=f'Y-intercept (0, {weights[3]:.2f})')
# Add title and labels
plt.title('Cubic Model')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.xlim([-0.25, max(X) + 1]) # Ensure the x-axis starts from 0
plt.show()
In this task, the learned 3rd order polynomial model is used to predict new labels for the new_inputs
array defined below.
plot_cubic_model_with_predictions
function.new_inputs = np.array([14, 1.5, -1])
# Function to plot data points, fitted cubic model, and predictions
def plot_cubic_model_with_predictions(X, y, weights, new_inputs, predicted_labels):
# Plot the original data points
plt.scatter(X, y, color='blue', label='Given Points')
# Plot the fitted cubic model
x_vals = np.linspace(min(min(X), min(new_inputs)), max(max(X), max(new_inputs)), 100)
y_vals = weights[0] * x_vals**3 + weights[1] * x_vals**2 + weights[2] * x_vals + weights[3]
plt.plot(
x_vals,
y_vals,
color='red',
label=(
f'Poly: y = {weights[0]:.2f}x^3 + {weights[1]:.2f}x^2 + '
f'{weights[2]:.2f}x + {weights[3]:.2f}'
))
# Plot the new inputs and their predicted labels
plt.scatter(new_inputs, predicted_labels, color='orange', label='Predicted Points')
# Add title, labels, and legend
plt.title('Learned Cubic Model with Predictions')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
#Write your reflection here...