{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "33c06ec81e90",
   "metadata": {},
   "source": [
    "# Lab 1: From Data to Insight\n",
    "\n",
    "## Exploratory Data Analysis with Python\n",
    "\n",
    "MPS311/439 Machine Learning · Week 1\n",
    "\n",
    "\n",
    "**Week 1 Lab Session | Core: 50 minutes | MPS439 extension: 30 minutes**\n",
    "\n",
    "## Introduction\n",
    "\n",
    "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)**.\n",
    "\n",
    "EDA helps us answer four questions:\n",
    "\n",
    "1. What does each row and column represent?\n",
    "2. Is the data complete and plausible?\n",
    "3. What patterns can we see?\n",
    "4. What can we responsibly conclude from those patterns?\n",
    "\n",
    "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.\n",
    "\n",
    "### Core learning outcomes\n",
    "\n",
    "By the end of the core lab, you should be able to:\n",
    "\n",
    "- load a CSV file into a pandas DataFrame;\n",
    "- inspect rows, columns, data types, and summary statistics;\n",
    "- identify missing values and duplicate rows;\n",
    "- create and label a histogram, bar chart, scatter plot, and line plot;\n",
    "- distinguish a **feature** from a **target**;\n",
    "- describe a pattern without claiming more than the data supports;\n",
    "- use AI to diagnose an error, then verify the proposed fix.\n",
    "\n",
    "> **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.\n",
    "\n",
    "### Files you need\n",
    "\n",
    "- This worksheet as a Jupyter Notebook.\n",
    "- [bike_rentals.csv](./bike_rentals.csv)\n",
    "\n",
    "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.\n",
    "\n",
    "---\n",
    "\n",
    "## Setup: Open, run, and save the notebook (5 minutes)\n",
    "\n",
    "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.\n",
    "\n",
    "Run the following cell without changing it.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb14d44c44df",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "\n",
    "DATA_FILE = \"bike_rentals.csv\"\n",
    "\n",
    "if not Path(DATA_FILE).exists():\n",
    "    try:\n",
    "        from google.colab import files\n",
    "        print(\"Choose bike_rentals.csv from your computer.\")\n",
    "        files.upload()\n",
    "    except ImportError:\n",
    "        raise FileNotFoundError(\n",
    "            \"bike_rentals.csv was not found. Place it in the same folder as this notebook.\"\n",
    "        )\n",
    "\n",
    "df = pd.read_csv(DATA_FILE)\n",
    "print(\"Dataset loaded successfully.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a14248508247",
   "metadata": {},
   "source": [
    "Now check that the object named `df` is a pandas DataFrame.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "64ff5d43bf7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "type(df)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a528164f1db",
   "metadata": {},
   "source": [
    "You should see `pandas.core.frame.DataFrame`.\n",
    "\n",
    "### Notebook check\n",
    "\n",
    "1. Change the message below.\n",
    "2. Run the cell.\n",
    "3. Change it again and re-run it.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d08a4d9875bc",
   "metadata": {},
   "outputs": [],
   "source": [
    "message = \"My Week 1 notebook is working.\"\n",
    "print(message)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7318bddac345",
   "metadata": {},
   "source": [
    "Save a copy of the notebook before continuing.\n",
    "\n",
    "- **Google Colab:** File -> Save a copy in Drive\n",
    "- **Jupyter:** File -> Save Notebook\n",
    "\n",
    "---\n",
    "\n",
    "## Part 1: Meet the dataset (8 minutes)\n",
    "\n",
    "### Background\n",
    "\n",
    "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.\n",
    "\n",
    "### Task 1.1: Preview the first rows\n",
    "\n",
    "Complete the method name.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76e1727469d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.____()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb07220f67e8",
   "metadata": {},
   "source": [
    "**Hint:** The method is `.head()`.\n",
    "\n",
    "### Task 1.2: Inspect the size and columns\n",
    "\n",
    "Fill in the blanks.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d30346e069d3",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"Rows and columns:\", df.____)\n",
    "print(\"Column names:\", df.____.tolist())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36319d239816",
   "metadata": {},
   "source": [
    "**Hints:**\n",
    "\n",
    "- `df.shape` gives `(number of rows, number of columns)`.\n",
    "- `df.columns` stores the column labels.\n",
    "\n",
    "Record your result:\n",
    "\n",
    "> Number of rows: __________  Number of columns: __________\n",
    "\n",
    "### Task 1.3: Understand the variables\n",
    "\n",
    "Run the following cell.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e24954ad3123",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.info()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1f81ef90f90",
   "metadata": {},
   "source": [
    "Use the table and the descriptions below.\n",
    "\n",
    "| Column | Meaning |\n",
    "|---|---|\n",
    "| `date` | Calendar date |\n",
    "| `day` | Day of the week |\n",
    "| `hour` | Hour of the day, from 0 to 23 |\n",
    "| `temperature_c` | Temperature in degrees Celsius |\n",
    "| `humidity_pct` | Relative humidity as a percentage |\n",
    "| `wind_speed_kmh` | Wind speed in kilometres per hour |\n",
    "| `weather` | Clear, Cloudy, or Rain |\n",
    "| `is_weekend` | 1 for Saturday/Sunday, otherwise 0 |\n",
    "| `rentals` | Number of bicycle rentals in that hour |\n",
    "\n",
    "Answer in your own words:\n",
    "\n",
    "1. What does one row represent?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "2. If our future goal is to predict bicycle rentals, which column is the **target**?\n",
    "\n",
    "> Target: ______________________________\n",
    "\n",
    "3. Give three columns that could be used as **features**.\n",
    "\n",
    "> Features: ____________________, ____________________, ____________________\n",
    "\n",
    "### Task 1.4: Summary statistics\n",
    "\n",
    "Complete and run the code.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6ed4fbcf68a6",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.____()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3554237c1443",
   "metadata": {},
   "source": [
    "**Hint:** Use `.describe()`.\n",
    "\n",
    "Look at `rentals`. Record its minimum, mean, and maximum.\n",
    "\n",
    "> Minimum: __________  Mean: __________  Maximum: __________\n",
    "\n",
    "**Think:** Does the mean describe a typical hour well, or might the distribution be uneven?\n",
    "\n",
    "---\n",
    "\n",
    "## Part 2: Check data quality (8 minutes)\n",
    "\n",
    "### Background\n",
    "\n",
    "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.\n",
    "\n",
    "### Task 2.1: Find missing values\n",
    "\n",
    "Fill in the method name.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bccef6e58f3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "missing_values = df.____().sum()\n",
    "print(missing_values)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af37f7c4e3de",
   "metadata": {},
   "source": [
    "**Hint:** Use `.isna()`.\n",
    "\n",
    "Which columns contain missing values?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "How many missing cells are there in total?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40a6eb33d9cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "total_missing = missing_values.____()\n",
    "print(\"Total missing cells:\", total_missing)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "182f878507ea",
   "metadata": {},
   "source": [
    "### Task 2.2: Find duplicate rows\n",
    "\n",
    "Complete the code.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c24aaacf21ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "duplicate_rows = df.____().sum()\n",
    "print(\"Duplicate rows:\", duplicate_rows)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "567afe354510",
   "metadata": {},
   "source": [
    "**Hint:** Use `.duplicated()`.\n",
    "\n",
    "### Task 2.3: Create a clean working copy\n",
    "\n",
    "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.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47ebd29876bd",
   "metadata": {},
   "outputs": [],
   "source": [
    "df_clean = (\n",
    "    df.drop_duplicates()\n",
    "      .dropna()\n",
    "      .copy()\n",
    ")\n",
    "\n",
    "print(\"Original shape:\", df.shape)\n",
    "print(\"Clean shape:   \", df_clean.shape)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99ba5945fa60",
   "metadata": {},
   "source": [
    "How many rows were removed?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4547dbbf04be",
   "metadata": {},
   "outputs": [],
   "source": [
    "rows_removed = len(____) - len(____)\n",
    "print(\"Rows removed:\", rows_removed)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "907632b06f8c",
   "metadata": {},
   "source": [
    "### Task 2.4: Debug with AI, then verify\n",
    "\n",
    "The code below contains an error. Run it and read the final line of the error message.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70de435d1578",
   "metadata": {},
   "outputs": [],
   "source": [
    "average_rentals = df_clean[\"rental\"].mean()\n",
    "print(average_rentals)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1da063cc4d5e",
   "metadata": {},
   "source": [
    "Ask an AI assistant:\n",
    "\n",
    "> I am learning pandas. Explain this error, identify the likely cause, and suggest the smallest change. Do not rewrite the full exercise.\n",
    "\n",
    "Then answer:\n",
    "\n",
    "1. What caused the error?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "2. What is the corrected line?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aaec5a39530b",
   "metadata": {},
   "outputs": [],
   "source": [
    "average_rentals = _______________________________________________\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f97d1fff80d",
   "metadata": {},
   "source": [
    "3. How did you verify that the fix was correct?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "---\n",
    "\n",
    "## Part 3: Explore individual variables (10 minutes)\n",
    "\n",
    "### Background\n",
    "\n",
    "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.\n",
    "\n",
    "### Task 3.1: Distribution of rentals\n",
    "\n",
    "Complete the column name, number of bins, and labels.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7fe0cc698f92",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(8, 5))\n",
    "plt.hist(df_clean[\"____\"], bins=____, color=\"steelblue\", edgecolor=\"white\")\n",
    "plt.xlabel(\"____________________\")\n",
    "plt.ylabel(\"____________________\")\n",
    "plt.title(\"____________________\")\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50b8815fe613",
   "metadata": {},
   "source": [
    "**Hints:**\n",
    "\n",
    "- Plot the `rentals` column.\n",
    "- Start with `bins=20`.\n",
    "- Every plot should say what the horizontal and vertical axes represent.\n",
    "\n",
    "Describe the shape of the distribution:\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "Are most observations near the low, middle, or high end?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "### Task 3.2: Count weather categories\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cfbe852ca4eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "weather_counts = df_clean[\"weather\"].____()\n",
    "print(weather_counts)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "632c1138cc82",
   "metadata": {},
   "source": [
    "**Hint:** Use `.value_counts()`.\n",
    "\n",
    "Now draw a bar chart.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b7ec5d914518",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(7, 4))\n",
    "weather_counts.plot(kind=\"____\", color=[\"#5e7ee8\", \"#e1a63d\", \"#7fa58d\"])\n",
    "plt.xlabel(\"Weather\")\n",
    "plt.ylabel(\"Number of hourly observations\")\n",
    "plt.title(\"Weather conditions in the dataset\")\n",
    "plt.xticks(rotation=0)\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1822b92b1180",
   "metadata": {},
   "source": [
    "Which weather category is most common?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "---\n",
    "\n",
    "## Part 4: Explore relationships (10 minutes)\n",
    "\n",
    "### Background\n",
    "\n",
    "Bivariate analysis studies the relationship between two variables. We will begin with a question:\n",
    "\n",
    "> Do warmer hours tend to have more bicycle rentals?\n",
    "\n",
    "### Task 4.1: Temperature and rentals\n",
    "\n",
    "Fill in the column names.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb2975d1675d",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(8, 5))\n",
    "plt.scatter(\n",
    "    df_clean[\"________________\"],\n",
    "    df_clean[\"________________\"],\n",
    "    alpha=0.55,\n",
    "    color=\"#3769cf\"\n",
    ")\n",
    "plt.xlabel(\"Temperature (C)\")\n",
    "plt.ylabel(\"Bicycle rentals per hour\")\n",
    "plt.title(\"Temperature and bicycle rentals\")\n",
    "plt.grid(alpha=0.2)\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5de4099729b3",
   "metadata": {},
   "source": [
    "Answer carefully:\n",
    "\n",
    "1. Is the overall relationship positive, negative, or unclear?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "2. Are there points that do not follow the overall pattern?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "3. Does this plot prove that higher temperature **causes** more rentals? Why or why not?\n",
    "\n",
    "> ______________________________________________________________________\n",
    ">\n",
    "> ______________________________________________________________________\n",
    "\n",
    "### Task 4.2: Hourly pattern\n",
    "\n",
    "Calculate the mean rentals for each hour.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bd3e7e5c995c",
   "metadata": {},
   "outputs": [],
   "source": [
    "hourly_rentals = df_clean.groupby(\"____\")[\"____\"].mean()\n",
    "\n",
    "plt.figure(figsize=(9, 5))\n",
    "plt.plot(hourly_rentals.index, hourly_rentals.values, marker=\"o\", color=\"#cc513f\")\n",
    "plt.xlabel(\"Hour of day\")\n",
    "plt.ylabel(\"Mean bicycle rentals\")\n",
    "plt.title(\"Average rental pattern across the day\")\n",
    "plt.xticks(range(0, 24, 2))\n",
    "plt.grid(alpha=0.2)\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46a6fc2ad2e7",
   "metadata": {},
   "source": [
    "At what times do rentals peak? Suggest one realistic explanation.\n",
    "\n",
    "> ______________________________________________________________________\n",
    ">\n",
    "> ______________________________________________________________________\n",
    "\n",
    "---\n",
    "\n",
    "## Part 5: Compare groups and investigate (6 minutes)\n",
    "\n",
    "### Task 5.1: Weekday versus weekend\n",
    "\n",
    "Complete the group and target columns.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f0362122f7b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "weekend_comparison = df_clean.groupby(\"___________\")[\"___________\"].mean()\n",
    "weekend_comparison.index = [\"Weekday\", \"Weekend\"]\n",
    "\n",
    "plt.figure(figsize=(6, 4))\n",
    "weekend_comparison.plot(kind=\"bar\", color=[\"#5e7ee8\", \"#ef6a4d\"])\n",
    "plt.xlabel(\"\")\n",
    "plt.ylabel(\"Mean bicycle rentals\")\n",
    "plt.title(\"Average rentals: weekday vs weekend\")\n",
    "plt.xticks(rotation=0)\n",
    "plt.tight_layout()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bfa9633a5ba",
   "metadata": {},
   "source": [
    "Which group has the higher overall mean?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "Why might an overall mean hide important hourly differences?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "### Task 5.2: Your mini-investigation\n",
    "\n",
    "Choose **one** question:\n",
    "\n",
    "1. How does humidity relate to rentals?\n",
    "2. How do rentals differ across Clear, Cloudy, and Rain conditions?\n",
    "3. Does the hourly rental pattern differ between weekdays and weekends?\n",
    "\n",
    "Create one appropriate plot. You may adapt code from earlier parts. Give the plot a meaningful title and label every axis.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1cb944c2907d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Write or adapt your code here.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34af92c8d97e",
   "metadata": {},
   "source": [
    "Write two evidence-based sentences:\n",
    "\n",
    "> Finding 1: ____________________________________________________________\n",
    ">\n",
    "> Finding 2: ____________________________________________________________\n",
    "\n",
    "Write one conclusion that your plot **cannot** support:\n",
    "\n",
    "> Limitation: ___________________________________________________________\n",
    "\n",
    "**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.\n",
    "\n",
    "---\n",
    "\n",
    "## Reflection and readiness check (3 minutes)\n",
    "\n",
    "Answer without running new code.\n",
    "\n",
    "1. What is the difference between a feature and a target?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "2. Why should we inspect missing values before creating a model?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "3. A scatter plot shows that rentals are higher in warmer hours. Give one possible confounding variable.\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "4. When AI suggests a code fix, what should you do before accepting it?\n",
    "\n",
    "> ______________________________________________________________________\n",
    "\n",
    "### Readiness checklist\n",
    "\n",
    "- [ ] I can load a CSV file into pandas.\n",
    "- [ ] I can inspect rows, columns, and data types.\n",
    "- [ ] I can check missing values and duplicates.\n",
    "- [ ] I can create a labelled plot.\n",
    "- [ ] I can describe a pattern without confusing association with causation.\n",
    "- [ ] I can read an error message and verify a proposed fix.\n",
    "\n",
    "If two or more items remain unclear, revisit the relevant section of Python Preparation before Week 2.\n",
    "\n",
    "---\n",
    "\n",
    "## Core summary\n",
    "\n",
    "Today you completed the first stage of a machine learning workflow:\n",
    "\n",
    "> **Question -> Data -> Check -> Visualise -> Interpret**\n",
    "\n",
    "You learned how to:\n",
    "\n",
    "- inspect a DataFrame;\n",
    "- identify simple data-quality issues;\n",
    "- explore numerical and categorical variables;\n",
    "- compare variables and groups visually;\n",
    "- distinguish features from a target;\n",
    "- communicate findings with appropriate caution.\n",
    "\n",
    "In Week 2, we will continue the workflow:\n",
    "\n",
    "> **Features + Target -> Model -> Prediction -> Evaluation**\n",
    "\n",
    "---\n",
    "\n",
    "# MPS439 Extension: Question-led EDA (30 minutes)\n",
    "\n",
    "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.\n",
    "\n",
    "## Extension 1: Build a reusable data audit (10 minutes)\n",
    "\n",
    "Write a function called `audit_dataframe(data)` that returns or prints:\n",
    "\n",
    "- number of rows and columns;\n",
    "- data type of every column;\n",
    "- missing-value count for every column;\n",
    "- number of duplicate rows;\n",
    "- numerical summary statistics.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fb3c7482a8c6",
   "metadata": {},
   "outputs": [],
   "source": [
    "def audit_dataframe(data):\n",
    "    \"\"\"Produce a compact quality report for a pandas DataFrame.\"\"\"\n",
    "    # Your implementation here.\n",
    "    pass\n",
    "\n",
    "\n",
    "audit_dataframe(df)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e72dc59aa81",
   "metadata": {},
   "source": [
    "**Challenge:** Make the output concise enough that you would genuinely use it at the start of a future project.\n",
    "\n",
    "## Extension 2: Multivariable visual exploration (10 minutes)\n",
    "\n",
    "Choose one of the following:\n",
    "\n",
    "### Option A: Weather changes the temperature-rentals relationship\n",
    "\n",
    "Create a scatter plot of temperature against rentals, using colour to distinguish `weather`.\n",
    "\n",
    "### Option B: Weekday and weekend hourly patterns\n",
    "\n",
    "Create two lines on the same plot: mean hourly rentals for weekdays and weekends.\n",
    "\n",
    "### Option C: Correlation heatmap\n",
    "\n",
    "Calculate correlations between numerical variables and create an annotated heatmap. Explain why correlation with `hour` or `is_weekend` must be interpreted carefully.\n",
    "\n",
    "You may use seaborn:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a82d652730e5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import seaborn as sns\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e81487de7eee",
   "metadata": {},
   "source": [
    "Your visualisation must include:\n",
    "\n",
    "- a clear analytical question;\n",
    "- an appropriate plot type;\n",
    "- readable labels and legend;\n",
    "- a caption explaining the main pattern.\n",
    "\n",
    "## Extension 3: EDA mini-report (10 minutes)\n",
    "\n",
    "Write a short report containing:\n",
    "\n",
    "1. **Question:** What did you investigate?\n",
    "2. **Evidence:** Which visual pattern supports your conclusion?\n",
    "3. **Interpretation:** What real-world mechanism might explain it?\n",
    "4. **Limitation:** What alternative explanation or missing variable matters?\n",
    "5. **Next step:** What would you investigate or model next?\n",
    "\n",
    "Aim for 150-250 words. Analytical depth matters more than the number of plots.\n",
    "\n",
    "## Extension reflection\n",
    "\n",
    "1. Which visualisation was most informative, and why?\n",
    "2. Did any plot change your initial assumption?\n",
    "3. Which variable would be most dangerous to interpret causally?\n",
    "4. What additional data would make the analysis more credible?\n",
    "\n",
    "---\n",
    "\n",
    "## Lab complete\n",
    "\n",
    "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.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
