Course: MPS311/439: Machine Learning
Lecturer: Dr. Wei Xing
How does Rightmove estimate a house's price without anyone visiting it? How can Netflix predict what show you'll enjoy next? How do businesses forecast quarterly sales? The answer lies in one of the most fundamental concepts in machine learning: prediction.
Prediction systems are embedded throughout modern life:
All of these tasks share a common structure: we want to predict a numerical value based on some available information.
Let's establish our foundational vocabulary:
Features (X): The input information we have available. These are the measurements or attributes we'll use to make predictions.
Target (y): The numerical value we want to predict. This is also called the "dependent variable" or "output."
Regression: The task of predicting a continuous numerical value (as opposed to classification, where we predict categories).
Let's work with a concrete example throughout these notes:
| House ID | Size (sq ft) | Bedrooms | Age (years) | Price (ยฃ) |
|---|---|---|---|---|
| 1 | 1,200 | 2 | 10 | 185,000 |
| 2 | 1,800 | 3 | 5 | 265,000 |
| 3 | 2,400 | 4 | 15 | 320,000 |
| 4 | 950 | 1 | 25 | 145,000 |
Our goal is to learn a model (function) that maps features to predictions:
f: X โ y
This function should work not just on houses we've seen before, but on new, unseen houses as well. This ability to work on new data is called generalization.
Let's start simple. Suppose we only use one feature: the size of the house. If we plot our data:
Price (ยฃ)
โ
340kโ โ
โ
280kโ โ
โ โ
220kโ
โ โ
160kโ
โ
100kโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ Size (sq ft)
800 1200 1600 2000 2400
What pattern do you see? The points roughly follow an upward trend. The simplest way to capture this pattern is with a straight line.
Remember from school mathematics: the equation of a line is y = mx + c, where:
In machine learning, we use slightly different notation:
Let's break down each component:
| Symbol | Name | Interpretation | School Math Equivalent |
|---|---|---|---|
| Predicted value | Our model's estimate (y-hat) | y | |
| Feature | Input value (e.g., house size) | x | |
| Weight | How much influence the feature has | m (slope) | |
| Bias | Baseline prediction when feature = 0 | c (intercept) |
Key Insight: The values and are called parameters. These are the numbers our model needs to learn from the data.
Let's say we learn that and for house prices in pounds and size in square feet:
What does this mean?
Example prediction:
For a 1,500 sq ft house:
We could draw infinitely many different lines through our data points:
Price
โ
โ Line A (steep)
โ โฑ
โ โ โฑ โ
โ โฑโ โฑ โ Line B (gentle)
โ โฑ โฑ โ โฑ
โโฑ โฑ โฑ
โ โฑโโโฑโโโโโโโโโ
โ โฑ
โโโโโโโโโโโโโโโโ Size
Question: Which line is "best"? How do we measure how well a line fits our data?
For each data point , we can measure the residual (error):
Where:
Price
โ
โ Actual point (yi)
โ โ
โ โโ Residual (error)
โ โ
โ ร Prediction (ลทi)
โ โฑ
โ โฑ Line
โ โฑ
โโโโโโโโโโโโโโโ Size
We can't just add up all the errors because positive and negative errors would cancel out. Instead, we square each error and then average:
Where:
Why square the errors?
- Squaring ensures all errors are positive (no cancellation)
- Larger errors get penalized more heavily (squared penalty)
- The resulting function is smooth and differentiable (important for optimization)
- It has a unique minimum (convex function)
Suppose we have 3 houses and our current parameters are , :
| House | Size () | Actual Price () | Predicted () | Error | Squared Error |
|---|---|---|---|---|---|
| 1 | 1,200 | 185,000 | 170,000 | 15,000 | 225,000,000 |
| 2 | 1,800 | 265,000 | 230,000 | 35,000 | 1,225,000,000 |
| 3 | 2,400 | 320,000 | 290,000 | 30,000 | 900,000,000 |
Our goal during training is to find the values of and that minimize this loss .
Training means finding the optimal parameters:
From calculus, we know that minima occur where the derivative equals zero. Since depends on two parameters, we need partial derivatives.
Starting with:
Taking the partial derivative with respect to :
Taking the partial derivative with respect to :
Setting both partial derivatives to zero:
This gives us a system of two linear equations with two unknowns. We can solve this system algebraically to find and (the optimal values).
This approach works beautifully for one feature. But what if we have:
We need a better approach. Enter: Linear Algebra.
Instead of working with individual numbers, we'll package everything into vectors and matrices. This allows us to handle any number of features elegantly.
Suppose we have features for each house:
We can write this more compactly using vector notation:
Weight vector:
Feature vector (note the 1 for the bias term):
Now our prediction is simply a dot product:
For training examples, we organize all features into a matrix (called the design matrix):
Each row is one training example (with a 1 prepended for the bias).
The target values for all examples go into a vector:
This is the mathematical heart of linear regression. Let's work through it step by step.
The loss function for all examples can be written as:
This is equivalent to summing the squared errors for all data points.
Using the rules of matrix algebra:
Derivation details:
The gradient of with respect to the vector is:
Using matrix calculus rules:
For the minimum, we set the gradient to zero:
Multiplying both sides by :
This is one of the most important equations in machine learning! It gives us the closed-form solution for the optimal weights.
Key properties:
Suppose we have data on houses:
Computing (conceptually):
The result might be:
Interpretation:
The beauty of modern machine learning libraries is that they implement the Normal Equation (and more efficient alternatives) for you. Here's how simple it is:
from sklearn.linear_model import LinearRegression
import numpy as np
# Our data
X = np.array([
[1200, 2], # Size, Bedrooms
[1800, 3],
[2400, 4],
[950, 1]
])
y = np.array([185000, 265000, 320000, 145000])
# Create and train the model
model = LinearRegression()
model.fit(X, y) # This computes the Normal Equation internally
# Get the learned parameters
print(f"Weights (w1, w2): {model.coef_}")
print(f"Bias (w0): {model.intercept_}")
# Make a prediction for a new house: 1500 sq ft, 2 bedrooms
new_house = np.array([[1500, 2]])
predicted_price = model.predict(new_house)
print(f"Predicted price: ยฃ{predicted_price[0]:,.0f}")
Output might look like:
Weights (w1, w2): [110.5 8234.2]
Bias (w0): 42156.8
Predicted price: ยฃ216,009
Every supervised machine learning project follows this pattern:
1. PREPARE DATA
โโ Load dataset
โโ Split into features (X) and target (y)
โโ Split into training and test sets
2. CREATE MODEL
โโ Instantiate the algorithm (e.g., LinearRegression())
3. TRAIN MODEL
โโ Call .fit(X_train, y_train)
4. EVALUATE MODEL
โโ Make predictions on test set
โโ Compute metrics (e.g., MSE, Rยฒ)
5. USE MODEL
โโ Make predictions on new, real data
Critical Concept: We train on one set of data and test on a different set.
Why? To check if our model generalizes to new data, or if it has simply memorized the training data (overfitting).
from sklearn.model_selection import train_test_split
# Split data: 80% training, 20% testing
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Train on training set only
model.fit(X_train, y_train)
# Evaluate on both sets
train_score = model.score(X_train, y_train)
test_score = model.score(X_test, y_test)
print(f"Training Rยฒ score: {train_score:.3f}")
print(f"Testing Rยฒ score: {test_score:.3f}")
If training score is much higher than testing score โ overfitting! (We'll address this next week with regularization)
There are other evaluation metrics that are more robust to outliers and can be used to evaluate the performance of the model.
Different metrics are more appropriate for different types of data and models. In General, MSE is the most common and most interpretable metric.
Regression is the task of predicting continuous numerical values
Linear models represent the relationship as:
Mean Squared Error (MSE) measures how well our model fits the data
Training finds the optimal parameters by minimizing the loss function
The Normal Equation gives us the closed-form solution
We must evaluate on a test set to check generalization
Today's lecture revealed a pattern you'll see repeatedly:
MODEL โ LOSS โ OPTIMIZATION
This framework applies to almost every supervised learning algorithm!
Our linear model is powerful but makes strong assumptions:
Next lecture (Week 3): We'll extend our model with:
๐ก Linear regression is simple but powerful
It's often the first model to try on a new problem
๐ก The Normal Equation is elegant
It shows that linear regression has a beautiful mathematical foundation
๐ก Always test on unseen data
Training performance alone doesn't tell you if your model will work in the real world
๐ก This framework generalizes
The pattern of Model โ Loss โ Optimization applies far beyond linear regression
For deeper understanding:
For practice:
sklearn Boston Housing or California Housing datasetsFor next week:
Conceptual: Why do we square the errors in MSE instead of just taking absolute values?
Mathematical: Given data points , , , use calculus to find optimal and for the model
Computational: Load a dataset from sklearn (e.g., diabetes dataset), fit a linear regression model, and compute the MSE on both training and test sets
Interpretation: If you have a model for predicting exam scores, where is hours studied and is previous test score, interpret what each coefficient means
"All models are wrong, but some are useful."
Remember: Linear regression is the foundation. Master it, and everything else becomes easier!
The Normal Equation is elegant, but has limitations:
For large datasets (millions of examples or thousands of features), we need an alternative: Gradient Descent.
Imagine you're hiking down a mountain in thick fog. You can't see the bottom, but you can feel which direction slopes downward. Gradient descent uses the same strategy:
Loss J(w)
โ
โ โ Start here (random w)
โ โฒ
โ โ Step 1
โ โฒ
โ โ Step 2
โ โฒ
โ โ Step 3
โ โฒ___โ Converge to minimum
โโโโโโโโโโโโโโโโโโโโโโโโ w
Initialize: Start with random weights
Repeat until convergence:
Where:
Update rule in detail:
Simplified (absorbing the 2 into ):
The learning rate is crucial:
Too large ฮฑ: Just right ฮฑ: Too small ฮฑ:
Loss Loss Loss
โ โ โ โ โ โ
โ โฒโฑโ โ โฒ โ โฒ
โ โฑ โฒ โ โฒโ โ โ
โ โ โ โ โ โ โ
โ โฒ โฑ โ โ โ โ
โ โ Oscillating! โ โ Converges โ โ Very slow
โโโโโโโโโโ w โโโโโโโโโโโ w โโโโโโโโโโโโ w
| Aspect | Normal Equation | Gradient Descent |
|---|---|---|
| Speed | Fast for small (<10,000) | Fast for large |
| Complexity | where = iterations | |
| Memory | ||
| Invertibility | Requires invertible | Always works |
| Implementation | One-step computation | Iterative process |
| Hyperparameters | None | Learning rate |
Practical Tip: For most standard regression problems with features, use the Normal Equation (what sklearn does by default). For very large-scale problems, gradient descent is essential.
import numpy as np
# Simple gradient descent implementation
def gradient_descent(X, y, alpha=0.01, iterations=1000):
n, p = X.shape
w = np.zeros(p) # Initialize weights to zero
for i in range(iterations):
# Compute predictions
y_pred = X @ w
# Compute gradient
gradient = -2/n * X.T @ (y - y_pred)
# Update weights
w = w - alpha * gradient
# Optionally: compute and print loss every 100 iterations
if i % 100 == 0:
loss = np.mean((y - y_pred)**2)
print(f"Iteration {i}: Loss = {loss:.2f}")
return w
# Use it
w_optimal = gradient_descent(X, y, alpha=0.01, iterations=1000)
Note: In practice, you'd use optimized implementations from libraries like sklearn (which can automatically choose between methods) or use SGDRegressor for explicit gradient-based optimization.