Lab 1: From Data to Insight
Exploratory Data Analysis with Python
Week 1 Lab Session | Core: 50 minutes | MPS439 extension: 30 minutes
Introduction
Welcome to your first machine learning lab. Before we train a model, we need to understand the data in front of us. This process is called exploratory data analysis (EDA).
EDA helps us answer four questions:
- What does each row and column represent?
- Is the data complete and plausible?
- What patterns can we see?
- What can we responsibly conclude from those patterns?
Today you will investigate hourly bicycle rentals. By the end of the lab, you should be able to inspect a dataset, identify simple data-quality issues, choose a suitable basic visualisation, and communicate one evidence-based finding.
Core learning outcomes
By the end of the core lab, you should be able to:
- load a CSV file into a pandas DataFrame;
- inspect rows, columns, data types, and summary statistics;
- identify missing values and duplicate rows;
- create and label a histogram, bar chart, scatter plot, and line plot;
- distinguish a feature from a target;
- describe a pattern without claiming more than the data supports;
- use AI to diagnose an error, then verify the proposed fix.
Need Python help? Use the Python Preparation guide for variables, methods, imports, and error messages. You do not need to memorise Python syntax to complete this lab.
Files you need
- This worksheet as a Jupyter Notebook.
- bike_rentals.csv
The dataset is synthetic and was created for teaching. It contains 14 days of hourly bicycle-rental observations. The patterns are realistic enough for EDA, but the data must not be presented as measurements from a real city.
Setup: Open, run, and save the notebook (5 minutes)
Download bike_rentals.csv from the Week 1 page and place it beside this notebook. If you are using Google Colab, the setup cell will ask you to upload the CSV when it cannot find the file.
Run the following cell without changing it.
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
DATA_FILE = "bike_rentals.csv"
if not Path(DATA_FILE).exists():
try:
from google.colab import files
print("Choose bike_rentals.csv from your computer.")
files.upload()
except ImportError:
raise FileNotFoundError(
"bike_rentals.csv was not found. Place it in the same folder as this notebook."
)
df = pd.read_csv(DATA_FILE)
print("Dataset loaded successfully.")Now check that the object named df is a pandas DataFrame.
type(df)You should see pandas.core.frame.DataFrame.
Notebook check
- Change the message below.
- Run the cell.
- Change it again and re-run it.
message = "My Week 1 notebook is working."
print(message)Save a copy of the notebook before continuing.
- Google Colab: File -> Save a copy in Drive
- Jupyter: File -> Save Notebook
Part 1: Meet the dataset (8 minutes)
Background
A DataFrame is a table with labelled rows and columns. Before plotting anything, we should understand what one row represents and what each column means.
Task 1.1: Preview the first rows
Complete the method name.
df.____()Hint: The method is .head().
Task 1.2: Inspect the size and columns
Fill in the blanks.
print("Rows and columns:", df.____)
print("Column names:", df.____.tolist())Hints:
df.shapegives(number of rows, number of columns).df.columnsstores the column labels.
Record your result:
Number of rows: __________ Number of columns: __________
Task 1.3: Understand the variables
Run the following cell.
df.info()Use the table and the descriptions below.
| Column | Meaning |
|---|---|
date |
Calendar date |
day |
Day of the week |
hour |
Hour of the day, from 0 to 23 |
temperature_c |
Temperature in degrees Celsius |
humidity_pct |
Relative humidity as a percentage |
wind_speed_kmh |
Wind speed in kilometres per hour |
weather |
Clear, Cloudy, or Rain |
is_weekend |
1 for Saturday/Sunday, otherwise 0 |
rentals |
Number of bicycle rentals in that hour |
Answer in your own words:
- What does one row represent?
- If our future goal is to predict bicycle rentals, which column is the target?
Target: ______________________________
- Give three columns that could be used as features.
Features: ____________________, ____________________, ____________________
Task 1.4: Summary statistics
Complete and run the code.
df.____()Hint: Use .describe().
Look at rentals. Record its minimum, mean, and maximum.
Minimum: __________ Mean: __________ Maximum: __________
Think: Does the mean describe a typical hour well, or might the distribution be uneven?
Part 2: Check data quality (8 minutes)
Background
Real datasets are rarely perfect. Missing values, repeated rows, and implausible values can change our conclusions. Code running without an error does not guarantee that the data is trustworthy.
Task 2.1: Find missing values
Fill in the method name.
missing_values = df.____().sum()
print(missing_values)Hint: Use .isna().
Which columns contain missing values?
How many missing cells are there in total?
total_missing = missing_values.____()
print("Total missing cells:", total_missing)Task 2.2: Find duplicate rows
Complete the code.
duplicate_rows = df.____().sum()
print("Duplicate rows:", duplicate_rows)Hint: Use .duplicated().
Task 2.3: Create a clean working copy
For this first lab, we will remove the duplicate row and the small number of rows containing missing values. In a real project, this decision would require more thought.
df_clean = (
df.drop_duplicates()
.dropna()
.copy()
)
print("Original shape:", df.shape)
print("Clean shape: ", df_clean.shape)How many rows were removed?
rows_removed = len(____) - len(____)
print("Rows removed:", rows_removed)Task 2.4: Debug with AI, then verify
The code below contains an error. Run it and read the final line of the error message.
average_rentals = df_clean["rental"].mean()
print(average_rentals)Ask an AI assistant:
I am learning pandas. Explain this error, identify the likely cause, and suggest the smallest change. Do not rewrite the full exercise.
Then answer:
- What caused the error?
- What is the corrected line?
average_rentals = _______________________________________________- How did you verify that the fix was correct?
Part 3: Explore individual variables (10 minutes)
Background
Univariate analysis studies one variable at a time. A histogram helps us see where numerical values are concentrated, while a bar chart helps us compare category counts.
Task 3.1: Distribution of rentals
Complete the column name, number of bins, and labels.
plt.figure(figsize=(8, 5))
plt.hist(df_clean["____"], bins=____, color="steelblue", edgecolor="white")
plt.xlabel("____________________")
plt.ylabel("____________________")
plt.title("____________________")
plt.tight_layout()
plt.show()Hints:
- Plot the
rentalscolumn. - Start with
bins=20. - Every plot should say what the horizontal and vertical axes represent.
Describe the shape of the distribution:
Are most observations near the low, middle, or high end?
Task 3.2: Count weather categories
weather_counts = df_clean["weather"].____()
print(weather_counts)Hint: Use .value_counts().
Now draw a bar chart.
plt.figure(figsize=(7, 4))
weather_counts.plot(kind="____", color=["#5e7ee8", "#e1a63d", "#7fa58d"])
plt.xlabel("Weather")
plt.ylabel("Number of hourly observations")
plt.title("Weather conditions in the dataset")
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()Which weather category is most common?
Part 4: Explore relationships (10 minutes)
Background
Bivariate analysis studies the relationship between two variables. We will begin with a question:
Do warmer hours tend to have more bicycle rentals?
Task 4.1: Temperature and rentals
Fill in the column names.
plt.figure(figsize=(8, 5))
plt.scatter(
df_clean["________________"],
df_clean["________________"],
alpha=0.55,
color="#3769cf"
)
plt.xlabel("Temperature (C)")
plt.ylabel("Bicycle rentals per hour")
plt.title("Temperature and bicycle rentals")
plt.grid(alpha=0.2)
plt.tight_layout()
plt.show()Answer carefully:
- Is the overall relationship positive, negative, or unclear?
- Are there points that do not follow the overall pattern?
- Does this plot prove that higher temperature causes more rentals? Why or why not?
Task 4.2: Hourly pattern
Calculate the mean rentals for each hour.
hourly_rentals = df_clean.groupby("____")["____"].mean()
plt.figure(figsize=(9, 5))
plt.plot(hourly_rentals.index, hourly_rentals.values, marker="o", color="#cc513f")
plt.xlabel("Hour of day")
plt.ylabel("Mean bicycle rentals")
plt.title("Average rental pattern across the day")
plt.xticks(range(0, 24, 2))
plt.grid(alpha=0.2)
plt.tight_layout()
plt.show()At what times do rentals peak? Suggest one realistic explanation.
Part 5: Compare groups and investigate (6 minutes)
Task 5.1: Weekday versus weekend
Complete the group and target columns.
weekend_comparison = df_clean.groupby("___________")["___________"].mean()
weekend_comparison.index = ["Weekday", "Weekend"]
plt.figure(figsize=(6, 4))
weekend_comparison.plot(kind="bar", color=["#5e7ee8", "#ef6a4d"])
plt.xlabel("")
plt.ylabel("Mean bicycle rentals")
plt.title("Average rentals: weekday vs weekend")
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()Which group has the higher overall mean?
Why might an overall mean hide important hourly differences?
Task 5.2: Your mini-investigation
Choose one question:
- How does humidity relate to rentals?
- How do rentals differ across Clear, Cloudy, and Rain conditions?
- Does the hourly rental pattern differ between weekdays and weekends?
Create one appropriate plot. You may adapt code from earlier parts. Give the plot a meaningful title and label every axis.
# Write or adapt your code here.
Write two evidence-based sentences:
Finding 1: ____________________________________________________________
Finding 2: ____________________________________________________________
Write one conclusion that your plot cannot support:
Limitation: ___________________________________________________________
AI Help: You may ask AI to recommend a plot type, but include the names and meanings of your variables. Decide for yourself whether its suggestion matches your question.
Reflection and readiness check (3 minutes)
Answer without running new code.
- What is the difference between a feature and a target?
- Why should we inspect missing values before creating a model?
- A scatter plot shows that rentals are higher in warmer hours. Give one possible confounding variable.
- When AI suggests a code fix, what should you do before accepting it?
Readiness checklist
If two or more items remain unclear, revisit the relevant section of Python Preparation before Week 2.
Core summary
Today you completed the first stage of a machine learning workflow:
Question -> Data -> Check -> Visualise -> Interpret
You learned how to:
- inspect a DataFrame;
- identify simple data-quality issues;
- explore numerical and categorical variables;
- compare variables and groups visually;
- distinguish features from a target;
- communicate findings with appropriate caution.
In Week 2, we will continue the workflow:
Features + Target -> Model -> Prediction -> Evaluation
MPS439 Extension: Question-led EDA (30 minutes)
The extension is intentionally open-ended. Do not produce extra plots without a purpose. Begin with a question, choose a visualisation that answers it, and explain what the result means.
Extension 1: Build a reusable data audit (10 minutes)
Write a function called audit_dataframe(data) that returns or prints:
- number of rows and columns;
- data type of every column;
- missing-value count for every column;
- number of duplicate rows;
- numerical summary statistics.
def audit_dataframe(data):
"""Produce a compact quality report for a pandas DataFrame."""
# Your implementation here.
pass
audit_dataframe(df)Challenge: Make the output concise enough that you would genuinely use it at the start of a future project.
Extension 2: Multivariable visual exploration (10 minutes)
Choose one of the following:
Option A: Weather changes the temperature-rentals relationship
Create a scatter plot of temperature against rentals, using colour to distinguish weather.
Option B: Weekday and weekend hourly patterns
Create two lines on the same plot: mean hourly rentals for weekdays and weekends.
Option C: Correlation heatmap
Calculate correlations between numerical variables and create an annotated heatmap. Explain why correlation with hour or is_weekend must be interpreted carefully.
You may use seaborn:
import seaborn as snsYour visualisation must include:
- a clear analytical question;
- an appropriate plot type;
- readable labels and legend;
- a caption explaining the main pattern.
Extension 3: EDA mini-report (10 minutes)
Write a short report containing:
- Question: What did you investigate?
- Evidence: Which visual pattern supports your conclusion?
- Interpretation: What real-world mechanism might explain it?
- Limitation: What alternative explanation or missing variable matters?
- Next step: What would you investigate or model next?
Aim for 150-250 words. Analytical depth matters more than the number of plots.
Extension reflection
- Which visualisation was most informative, and why?
- Did any plot change your initial assumption?
- Which variable would be most dangerous to interpret causally?
- What additional data would make the analysis more credible?
Lab complete
Keep your completed notebook. The EDA habits from this lab - checking quality, choosing purposeful plots, and explaining limitations - will be expected throughout the course and in both assessments.
30-second feedback
Scan the code to share anonymous feedback or post a question for this lab. It opens the correct Week 01 lab record automatically.