Predict Housing Prices with ML

Train a linear regression model to predict California housing prices.

Introduction

30 Second Summary

Every time you browse a real estate listing, an algorithm is working behind the scenes to estimate property values. These predictions influence pricing, lending, and investment decisions across the housing market.

In this project, you will build a machine learning model that predicts California housing prices using real census data. You'll follow the same workflow that ML engineers use every day to load data, train a model, and evaluate its accuracy.

What You'll Build

A Python script that loads 20,640 housing records, trains a Linear Regression model, and outputs predicted prices alongside evaluation metrics and a scatter plot visualization.

By the end of this project, you'll have:

  • A trained Linear Regression model that predicts housing prices from features like median income, house age, and location.
  • Printed evaluation metrics (R² score and Mean Absolute Error) showing how well your model performs.
  • A matplotlib scatter plot comparing predicted vs actual prices to visualize model accuracy.
  • Secret Mission: Swap in a Random Forest model and compare its performance against Linear Regression.

Are there any prerequisites?

You'll need basic Python knowledge (variables, functions, and loops). No prior machine learning experience is required.

Set Up Your Python Environment

Before you can train a machine learning model, you need the right tools installed. The libraries you'll use in this project require Python 3.11 or higher to run correctly.

In this step, you'll confirm your Python version, create an isolated environment for the project, and install three key libraries: scikit-learn for machine learning, pandas for data exploration, and matplotlib for visualization.

In this step, get ready to:
  • Verify that Python 3.11+ is installed on your machine.
  • Create and activate a virtual environment for the project.
  • Install scikit-learn, pandas, and matplotlib.
Verify your Python version

The libraries you'll install require Python 3.11 or higher. Let's confirm what version you have.

  • In VS Code, open the integrated terminal by pressing Ctrl+` (macOS) or Ctrl+` (Windows).
  • Check your Python version by running this command:

macOS

python3 --version

Windows

python --version

You should see a version number printed in the terminal.

✔️ I see version 3.11 or higher

Your Python version is ready. Move on to the next substep.

ⓧ I see an older version

Your system has an older version of Python installed. You need 3.11 or higher for this project.

  • Download the latest Python from python.org/downloads.
  • Run the installer and follow the prompts.
  • On Windows, make sure to check Add Python to PATH during installation.
  • Close and reopen your terminal in VS Code, then re-run the version check command above.

macOS and the default Python version

macOS ships with an older Python by default. Even after installing a newer version, the python3 command may still point to the old one.

If python3 --version still shows an old version after installing, try running python3.11 --version or python3.14 --version (using the version you downloaded). If that works, use that command in place of python3 throughout this project.

ⓧ Command not found

Python is not installed on your machine yet.

  • Download the latest Python from python.org/downloads.
  • Run the installer and follow the prompts.
  • On Windows, make sure to check Add Python to PATH during installation.
  • Close and reopen your terminal in VS Code, then run the version check command above.
Create a virtual environment and activate it

A virtual environment keeps your project's libraries separate from other Python projects on your machine. This prevents version conflicts between projects.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir housing-predictor
cd housing-predictor
  • Confirm the folder exists by running:
ls

You should see an empty directory (no files listed yet).

  • Create a virtual environment inside this folder by running:

macOS

python3 -m venv ml-env

Windows

python -m venv ml-env
  • Activate the virtual environment by running:

macOS

source ml-env/bin/activate

Windows

ml-env\Scripts\activate

You should see (ml-env) appear at the beginning of your terminal prompt. This confirms the virtual environment is active.

What is a virtual environment?

Think of it like a clean workspace. Any libraries you install while the virtual environment is active only live inside the ml-env folder. They won't interfere with other projects on your system.

Don't see (ml-env) in your prompt?

On Windows, if you get a permissions error when activating, you may need to allow script execution. Run Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned in PowerShell first, then try the activate command again.

On macOS, make sure you used source before the path. Running the script directly without source will not activate the environment in your current terminal session.

Help me activate my virtual environment.

Install the required libraries

With your virtual environment active, you can now install the three libraries this project needs.

  • Install scikit-learn, pandas, and matplotlib by running:
pip install scikit-learn pandas matplotlib

What are these libraries?

scikit-learn provides machine learning algorithms like Linear Regression and tools for splitting data. pandas makes it easy to explore and manipulate tabular data. matplotlib creates charts and visualizations.

The install may take a minute. You'll see progress bars as each package downloads.

  • Verify that scikit-learn installed correctly by running:

macOS

python3 -c "import sklearn; print(sklearn.__version__)"

Windows

python -c "import sklearn; print(sklearn.__version__)"

You should see a version number like 1.8.0 printed in the terminal. This confirms scikit-learn is installed and importable.

Seeing a ModuleNotFoundError?

Make sure (ml-env) is visible in your terminal prompt. If it's missing, the virtual environment is not active and Python is looking in the wrong location for packages.

Run the activate command from the previous substep, then try the import check again.

Help me fix my scikit-learn import error.

Your environment is ready. Next up, you'll load a real dataset of California housing records and start exploring what drives home prices.

Load and Explore the Dataset

Your Python environment is ready with all the tools installed. Now it's time to get your hands on some real data.

In this step, you'll load the California Housing dataset and explore what's inside it. This dataset contains 20,640 records from the 1990 U.S. Census, each describing a California district with features like median income, house age, and population.

In this step, get ready to:
  • Load a real-world housing dataset into Python.
  • Explore the data to understand its structure and features.
  • Identify what the model will predict (the target variable).
Create your prediction script and load the data

The California Housing dataset comes built into scikit-learn. You don't need to download any external files.

  • Press Cmd+N (macOS) or Ctrl+N (Windows) in VS Code to create a new file.
  • Press Cmd+S (macOS) or Ctrl+S (Windows) to save it immediately.
  • Name the file housing_predictor.py and save it in your current working directory.
  • Add the following imports to the top of the file:
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

What do these imports do?

  • pandas gives you DataFrames for exploring tabular data.
  • matplotlib.pyplot lets you create charts and visualizations.
  • The sklearn imports bring in the dataset, data splitting utility, model, and evaluation metrics you'll use throughout the project.
  • Add the following code below your imports to load the dataset and convert it to a DataFrame:
# Step 2: Load and explore the dataset
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target

What does this code do?

  • fetch_california_housing() loads the dataset from scikit-learn's built-in collection. No file download needed.
  • pd.DataFrame(...) converts the raw data into a table with named columns so you can explore it easily.
  • df['MedHouseVal'] = housing.target adds the target column (what you'll predict) to the DataFrame.
Explore the dataset

Before training a model, you need to understand the shape and content of your data. Exploration helps you catch issues early and build intuition about what the model has to work with.

  • Add the following code below your loading section to print key information about the dataset:
print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nFeature names:", housing.feature_names)
print("\nBasic statistics:")
print(df.describe())
print("\nTarget variable (MedHouseVal) is median house value in $100,000s")

What does this code do?

  • df.shape shows the number of rows and columns (20,640 rows, 9 columns).
  • df.head() displays the first 5 rows so you can see actual data values.
  • housing.feature_names lists all 8 input features the model can learn from.
  • df.describe() calculates summary statistics like mean, min, and max for each column.
  • Save housing_predictor.py.
  • Run the script in your terminal by entering this command:
python housing_predictor.py
  • You should see the dataset shape (20640, 9), a table of the first 5 rows, the list of 8 feature names, and a statistics summary.

Not seeing any output?

  • Make sure your virtual environment is still active. You should see (ml-env) at the start of your terminal prompt.
  • Check that you saved the file before running it. Unsaved changes won't execute.
  • If you see a ModuleNotFoundError, your packages may not be installed in the active environment. Re-run pip install scikit-learn pandas matplotlib with the virtual environment active.

help me debug my housing_predictor.py script

Understand the target variable

Look at the last line of your output. It tells you that MedHouseVal is measured in units of $100,000.

What does MedHouseVal mean?

MedHouseVal is the median house value for each California district. A value of 2.5 means the median house in that district costs $250,000.

This is what your model will learn to predict. Given features like median income and house age, the model figures out the relationship between those inputs and the house value.

What do the feature names mean?

  • MedInc = median income of households in the district.
  • HouseAge = median age of houses in the district.
  • AveRooms = average number of rooms per household.
  • AveBedrms = average number of bedrooms per household.
  • Population = total population of the district.
  • AveOccup = average number of occupants per household.
  • Latitude and Longitude = geographic coordinates of the district.

✔️ Awesome, I've got everything!

Great. Double check you've saved housing_predictor.py and that your output shows all 8 feature names and the statistics table.

ⓧ I'd like to double check the full code

Here's the complete housing_predictor.py file so far:

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

# Step 2: Load and explore the dataset
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target

print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nFeature names:", housing.feature_names)
print("\nBasic statistics:")
print(df.describe())
print("\nTarget variable (MedHouseVal) is median house value in $100,000s")

You now have a clear picture of what your data looks like. Next up, you'll split this data into training and testing sets so your model can learn from one portion and be evaluated on another.

Prepare the Data for Training

In Step 2, you loaded over 20,000 California housing records and explored the data to understand its shape and features. Now you know what you're working with.

Before your model can learn anything, you need to organize the data into the right format. You also need to hold back some data so you can test how well the model performs on data it has never seen.

In this step, get ready to:
  • Separate features (X) and target (y) from the dataset.
  • Split the data into training and testing sets.
  • Print shapes to confirm the split worked correctly.
Split the dataset into features, target, and train/test sets

What are features and target in machine learning?

In supervised learning, features are the input columns the model uses to make predictions. The target is the output column you want the model to learn to predict.

Think of it like studying for an exam. Features are the study materials (income, house age, location). The target is the correct answer (house price). You give the model lots of examples so it can learn the relationship between inputs and outputs.

Why split data into training and testing?

If you test a model on the same data it trained on, it can just memorize the answers. Holding back 20% of the data as a test set lets you measure how well the model handles new, unseen data.

Setting random_state=42 makes the split reproducible. Every time you run the script, the same rows end up in training and testing. This makes your results consistent and comparable.

  • In housing_predictor.py, scroll to the bottom of the file (below the last print statement) and add the following code:
# Step 3: Prepare the data
X = df.drop('MedHouseVal', axis=1)
y = df['MedHouseVal']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print(f"\nTraining set size: {X_train.shape[0]} samples")
print(f"Test set size: {X_test.shape[0]} samples")

What does this code do?

  • X = df.drop('MedHouseVal', axis=1) creates your features matrix by taking every column EXCEPT the target. This gives the model 8 input features like median income, house age, and location.
  • y = df['MedHouseVal'] isolates the target column. This is what the model will learn to predict.
  • train_test_split randomly shuffles the data and splits it. 80% goes to training (X_train, y_train) and 20% goes to testing (X_test, y_test).
  • The print statements confirm how many samples ended up in each set, so you can verify the 80/20 split worked.
  • Save housing_predictor.py.
  • Run the script in your terminal by running:
python housing_predictor.py
  • At the bottom of the output (after the dataset exploration from Step 2), you should see:
Training set size: 16512 samples
Test set size: 4128 samples

Not seeing the training/test sizes?

  • Make sure you saved housing_predictor.py before running the script.
  • Check that your new code is below the exploration print statements, not inside them or above them.
  • If you see a NameError for df, make sure the Step 2 code that creates the DataFrame is still above your new code.

Why isn't my training/test split printing correctly?

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the complete housing_predictor.py so far. Compare your file against this:

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

# Step 2: Load and explore the dataset
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target

print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nFeature names:", housing.feature_names)
print("\nBasic statistics:")
print(df.describe())
print("\nTarget variable (MedHouseVal) is median house value in $100,000s")

# Step 3: Prepare the data
X = df.drop('MedHouseVal', axis=1)
y = df['MedHouseVal']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print(f"\nTraining set size: {X_train.shape[0]} samples")
print(f"Test set size: {X_test.shape[0]} samples")

Your data is prepped and ready. You have 16,512 examples for the model to learn from and 4,128 held back for testing. Next up, you'll train your first machine learning model and see how accurately it can predict housing prices.

Train and Evaluate Your Model

Your data is split and ready to go. Now comes the exciting part: teaching a model to predict housing prices from the patterns in your training data.

In this step, you will train a Linear Regression model and measure how accurate its predictions are. You will also create a visual chart comparing what the model predicted against the actual housing prices.

In this step, get ready to:
  • Train a Linear Regression model on your training data.
  • Evaluate your model's accuracy using R² score and Mean Absolute Error.
  • Create a scatter plot comparing predicted vs actual housing prices.
Train the model and calculate accuracy metrics

Training a model means feeding it examples (your training data) so it can learn the relationship between features and the target price. Once trained, you test it on data it has never seen before to measure how well it generalizes.

  • In housing_predictor.py, scroll to the bottom of the file (after the print(f"Test set size: ... line).
  • Add the following code to train the model, make predictions, and print evaluation metrics:
# Step 4: Train and evaluate the model
model = LinearRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)

r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)

print(f"\n--- Linear Regression Results ---")
print(f"R² Score: {r2:.4f}")
print(f"Mean Absolute Error: ${mae * 100000:.2f}")

What does this code do?

This code covers the core machine learning loop in three stages:

  • model = LinearRegression() creates a fresh model, and .fit() trains it by finding the best-fit line through the training data.
  • .predict(X_test) asks the trained model to guess prices for the test data it has never seen.
  • r2_score measures the percentage of price variation the model explains (1.0 = perfect). mean_absolute_error shows the average dollar amount the predictions are off by.
  • Save housing_predictor.py.
  • Run the script in your terminal by running:
python housing_predictor.py
  • Scroll to the bottom of the output. You should see a section titled --- Linear Regression Results --- with an R² Score around 0.60 and a Mean Absolute Error around $50,000.

What do these numbers mean?

An R² of 0.60 means the model explains about 60% of what drives housing prices. That is decent for a simple linear model but leaves room for improvement.

An MAE of ~$50,000 means the model's predictions are off by about $50,000 on average. You will see in the Secret Mission how a more advanced model can do better.

Seeing an error when you run the script?

  • Check that your virtual environment is still active. You should see (ml-env) at the start of your terminal prompt.
  • Make sure the new code is pasted AFTER the existing Step 3 code, not inside it.
  • Verify that X_train and y_train are defined earlier in your file from the train_test_split call.

Why is my model training failing?

Visualize predictions with a scatter plot

Numbers are useful, but a chart shows you at a glance how well the model performs across all price ranges. A perfect model would place every dot along a straight diagonal line.

  • Add the following code below the print statements you just added to create a scatter plot comparing predicted vs actual prices:
# Scatter plot: predicted vs actual
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, alpha=0.3, s=10)
plt.plot([0, 5], [0, 5], 'r--', label='Perfect prediction')
plt.xlabel('Actual Price ($100,000s)')
plt.ylabel('Predicted Price ($100,000s)')
plt.title('Linear Regression: Predicted vs Actual Housing Prices')
plt.legend()
plt.tight_layout()
plt.savefig('prediction_plot.png')
plt.show()

What does this code do?

  • plt.scatter(y_test, y_pred) plots each test sample as a dot. The x-axis is the real price, the y-axis is what the model predicted.
  • plt.plot([0, 5], [0, 5], 'r--') draws a red dashed diagonal line representing perfect predictions. The closer dots are to this line, the better the model.
  • plt.savefig('prediction_plot.png') saves the chart as an image file so you have a record of your results.
  • Save housing_predictor.py and run the script again:
python housing_predictor.py
  • A scatter plot window should pop up showing blue dots clustered around the red diagonal line. Close the plot window when you are done inspecting it.
  • Confirm that prediction_plot.png was saved in your project folder by running:
ls
  • You should see prediction_plot.png listed alongside housing_predictor.py.

Plot window not showing up?

  • Some environments run matplotlib without a display backend. The chart is still saved as prediction_plot.png in your project folder. Open it manually to view your results.
  • Make sure matplotlib is installed in your virtual environment. Run pip install matplotlib if you skipped it earlier.

Why isn't my matplotlib plot displaying?

✔️ Awesome, I've got everything!

Great. Double check you have saved housing_predictor.py before moving on.

ⓧ I'd like to double check the full code

Here is the complete housing_predictor.py file up to this point. Compare your file against this:

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

# Step 2: Load and explore the dataset
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target

print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nFeature names:", housing.feature_names)
print("\nBasic statistics:")
print(df.describe())
print("\nTarget variable (MedHouseVal) is median house value in $100,000s")

# Step 3: Prepare the data
X = df.drop('MedHouseVal', axis=1)
y = df['MedHouseVal']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print(f"\nTraining set size: {X_train.shape[0]} samples")
print(f"Test set size: {X_test.shape[0]} samples")

# Step 4: Train and evaluate the model
model = LinearRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)

r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)

print(f"\n--- Linear Regression Results ---")
print(f"R² Score: {r2:.4f}")
print(f"Mean Absolute Error: ${mae * 100000:.2f}")

# Scatter plot: predicted vs actual
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, alpha=0.3, s=10)
plt.plot([0, 5], [0, 5], 'r--', label='Perfect prediction')
plt.xlabel('Actual Price ($100,000s)')
plt.ylabel('Predicted Price ($100,000s)')
plt.title('Linear Regression: Predicted vs Actual Housing Prices')
plt.legend()
plt.tight_layout()
plt.savefig('prediction_plot.png')
plt.show()

Your model is trained and evaluated. Next up, you will use it to predict housing prices for brand new data and discover which features matter most.

Make Predictions on New Data

Your model is trained and you know how accurate it is. But a model sitting on a shelf isn't useful. The real value comes from feeding it new data and getting predictions back.

In this step, you'll create a hypothetical California district and ask your model to predict its housing price. You'll also peek inside the model to see which features it relies on most.

In this step, get ready to:
  • Make a prediction on a new hypothetical district.
  • Analyze feature importances to understand what drives predictions.
Predict a price for a new district

Your model learned patterns from 16,512 training samples. Now you'll give it a brand-new set of values it has never seen and ask it to predict the median house value.

  • In housing_predictor.py, scroll to the very bottom of the file (after the plt.show() line).
  • Add the following code to create a sample district and predict its price:
# Step 5: Make predictions on new data
import numpy as np

sample = np.array([[5.0, 20.0, 5.0, 1.0, 1500.0, 3.0, 37.0, -122.0]])
predicted_price = model.predict(sample)
print(f"\nPrediction for sample district:")
print(f"  Median Income: 5.0 ($50,000)")
print(f"  House Age: 20 years")
print(f"  Predicted Median House Value: ${predicted_price[0] * 100000:.2f}")

What does this code do?

You're creating a NumPy array with 8 values. Each value corresponds to one of the dataset's features in order: MedInc, HouseAge, AveRooms, AveBedrms, Population, AveOccup, Latitude, Longitude.

The sample represents a district with a median income of $50,000, houses around 20 years old, located in Northern California. The model uses the patterns it learned during training to estimate what the median house value would be in this district.

  • Save housing_predictor.py.
  • Run the script by running this command in your terminal:
python housing_predictor.py
  • Close the scatter plot window when it appears. After closing, you should see a "Prediction for sample district" section in the terminal output showing the predicted house value in dollars.

Not seeing the prediction output?

The scatter plot window from the previous step blocks the script. Close the plot window and the remaining output will appear in the terminal.

If you see a shape error, make sure your sample array has exactly 8 values inside double brackets [[...]]. The outer brackets create a 2D array that the model expects.

Why isn't my model prediction appearing after the scatter plot?

Print feature importances

A prediction is useful, but understanding WHY the model predicts a certain value is even more valuable. Linear Regression stores a coefficient for each feature. Larger absolute values mean the feature has more influence on the prediction.

  • Add this code at the bottom of housing_predictor.py, below the prediction print statements:
# Feature importances (coefficients)
print(f"\n--- Feature Importances (Coefficients) ---")
for feature, coef in zip(housing.feature_names, model.coef_):
    print(f"  {feature}: {coef:.4f}")

What does this code do?

The model.coef_ attribute contains the weight the model assigns to each feature. A positive coefficient means the feature increases the predicted price. A negative coefficient means it decreases it.

The zip() function pairs each feature name with its corresponding coefficient so you can see them side by side.

  • Save housing_predictor.py and run the script again:
python housing_predictor.py
  • Close the scatter plot window. You should see a "Feature Importances (Coefficients)" table in the terminal listing all 8 features with their coefficient values. MedInc (median income) should have the largest positive coefficient, confirming it is the strongest predictor of housing prices.

Why is median income the strongest predictor?

This makes intuitive sense. The median income of a neighborhood is strongly correlated with how expensive houses are there. Wealthier neighborhoods command higher prices.

Notice that Latitude and Longitude also have significant coefficients. Location matters for housing prices, and the model captured that pattern from the data.

Seeing an AttributeError for coef_?

Make sure the feature importance code comes after model.fit(X_train, y_train) in your file. The coef_ attribute only exists after the model has been trained.

Why is my model showing an AttributeError for coef_?

✔️ Awesome, I've got everything!

Great. Double check you've saved your file.

ⓧ I'd like to double check the full code

Here is the complete housing_predictor.py file. Compare yours against it:

import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, r2_score

# Step 2: Load and explore the dataset
housing = fetch_california_housing()
df = pd.DataFrame(housing.data, columns=housing.feature_names)
df['MedHouseVal'] = housing.target

print("Dataset shape:", df.shape)
print("\nFirst 5 rows:")
print(df.head())
print("\nFeature names:", housing.feature_names)
print("\nBasic statistics:")
print(df.describe())
print("\nTarget variable (MedHouseVal) is median house value in $100,000s")

# Step 3: Prepare the data
X = df.drop('MedHouseVal', axis=1)
y = df['MedHouseVal']

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print(f"\nTraining set size: {X_train.shape[0]} samples")
print(f"Test set size: {X_test.shape[0]} samples")

# Step 4: Train and evaluate the model
model = LinearRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)

r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)

print(f"\n--- Linear Regression Results ---")
print(f"R\u00b2 Score: {r2:.4f}")
print(f"Mean Absolute Error: ${mae * 100000:.2f}")

# Scatter plot: predicted vs actual
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, alpha=0.3, s=10)
plt.plot([0, 5], [0, 5], 'r--', label='Perfect prediction')
plt.xlabel('Actual Price ($100,000s)')
plt.ylabel('Predicted Price ($100,000s)')
plt.title('Linear Regression: Predicted vs Actual Housing Prices')
plt.legend()
plt.tight_layout()
plt.savefig('prediction_plot.png')
plt.show()

# Step 5: Make predictions on new data
import numpy as np

sample = np.array([[5.0, 20.0, 5.0, 1.0, 1500.0, 3.0, 37.0, -122.0]])
predicted_price = model.predict(sample)
print(f"\nPrediction for sample district:")
print(f"  Median Income: 5.0 ($50,000)")
print(f"  House Age: 20 years")
print(f"  Predicted Median House Value: ${predicted_price[0] * 100000:.2f}")

# Feature importances (coefficients)
print(f"\n--- Feature Importances (Coefficients) ---")
for feature, coef in zip(housing.feature_names, model.coef_):
    print(f"  {feature}: {coef:.4f}")

Secret mission

Compare with Random Forest

Your Linear Regression model draws a straight line through the data. But what if you could use a model that captures more complex patterns? In this mission, you'll train a Random Forest and compare it head-to-head against Linear Regression to see the difference model choice makes.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your resources for future experimentation, pause them to free up terminal processes, or delete them entirely.

Resources you used:

  • Virtual environment ml-env (contains scikit-learn, pandas, and matplotlib).
  • Python script housing_predictor.py.
  • Generated plot images: prediction_plot.png and model_comparison_plot.png.

Keep everything running

No action needed. Choose this if you plan to keep experimenting with your model or want to tweak features and retrain.

  • Your virtual environment stays active and ready to use.
  • Your script and plots remain on disk for future reference.
  • You can re-run housing_predictor.py any time to regenerate predictions.

Pause - I'll come back to this later

Deactivate the virtual environment to free up your terminal session. Your files and installed packages remain on disk for when you return.

  • Deactivate the virtual environment by running:
deactivate

When you want to resume, reactivate the environment with:

macOS

source ml-env/bin/activate

Windows

ml-env\Scripts\activate

Delete - I don't want to use this again

Remove all project files and the virtual environment to start fresh. This deletes everything you created in this project.

  • Deactivate the virtual environment first:
deactivate
  • Delete the virtual environment folder and all project files:

macOS

rm -rf ml-env
rm housing_predictor.py prediction_plot.png model_comparison_plot.png

Windows

rmdir /s /q ml-env
del housing_predictor.py prediction_plot.png model_comparison_plot.png
  • Confirm everything is removed by running:
ls

You should no longer see ml-env, housing_predictor.py, or the plot files in the output.

Nice Work!

Nice Work!

You just built a complete machine learning pipeline from scratch. Your model can now predict California housing prices using real census data from 20,640 districts.

You've learned how to:

  • Trained a Linear Regression model on real-world California census data and used it to predict housing prices.
  • Evaluated model accuracy using R² score and Mean Absolute Error, then visualized predictions against actual values with a scatter plot.
  • Made predictions on unseen data and analysed feature importances to understand which factors drive housing prices.
  • Compared Linear Regression against a Random Forest model to see how model choice impacts prediction accuracy.

Ready to quiz yourself?