Skip to learning content

DATA SCIENCE PYTHON PLAYGROUND

Data Foundations

← All challenges
VC07 · Delivery / logistics · ~10–20 min

Compare spread, not just averages

data quality · distribution · outliers

Spread comparison

The question

Compare the centre and spread of delivery durations across depots.

df Spread comparison

Your inputs

df

One row is a completed delivery. Durations include unknown values and a genuine long delivery; do not discard an observation merely because it is unusual.

Field meanings and units
delivery_id
Delivery identifier.
depot
Depot responsible for the delivery.
status
Recorded delivery state.
minutes
Elapsed duration in minutes; unknown is not zero.
weight_kg
Weight in kilograms.
date
Calendar date supplied as YYYY-MM-DD text unless the task states it is invalid.
df · first 5 of 24 rows
delivery_iddepotstatusminutesweight_kgdate
D001EastDelivered321.22026-04-01
D002WestDelivered481.92026-04-01
D003NorthDelivered252.62026-04-02
D004EastDeliveredNone3.32026-04-02
D005WestDelivered4542026-04-03
View all 24 rows
df · complete input
delivery_iddepotstatusminutesweight_kgdate
D001EastDelivered321.22026-04-01
D002WestDelivered481.92026-04-01
D003NorthDelivered252.62026-04-02
D004EastDeliveredNone3.32026-04-02
D005WestDelivered4542026-04-03
D006NorthDelivered371.22026-04-03
D007EastDelivered721.92026-04-04
D008WestDelivered292.62026-04-04
D009NorthDeliveredbad3.32026-04-05
D010EastDelivered4942026-04-05
D011WestDelivered261.22026-04-06
D012NorthDelivered621.92026-04-06
D013EastDelivered462.62026-04-07
D014WestDelivered383.32026-04-07
D015NorthDelivered7342026-04-08
D016EastDelivered301.22026-04-08
D017WestDelivered341.92026-04-09
D018NorthDelivered502.62026-04-09
D019EastDelivered273.32026-04-10
D020WestDelivered6342026-04-10
D021NorthDelivered471.22026-04-11
D022EastDelivered1801.92026-04-11
D023WestDelivered742.62026-04-12
D024NorthDelivered313.32026-04-12

The editable setup in Your Python creates these inputs when you run it.

Your task · Compare spread, not just averages

Compare the centre and spread of delivery durations across depots.

observationsDataFramefigFigure

Deliverables

Make the outputs listed below. Use each name exactly as shown. Then choose Check answer.

Python name key

Teal outlines name table columns. Violet left rules name Python objects. Dotted rules mark syntax, functions and parameters. Use each name exactly as shown.

  1. Valid delivery measurementsOutputobservationsDataFrame
    1. Create observations with depot and parsed minutes for known durations, keeping source order.
  2. FigureOutputfigFigure
    1. Create fig comparing depot medians, middle 50%, and 1.5-IQR whiskers, including outliers.
    2. Put depots on the horizontal axis and minutes on the vertical axis.
    3. Add a meaningful title and labels
    4. Display the figure.

    Identify Depot and Minutes on the appropriate axes; extra wording is welcome.

Data policy Keep all supplied source tables unchanged. Work on separate outputs.

Help Hints & explained solution

Choose the amount of help you need. Opening one hint does not reveal the others.

Hint 1 — Think

What could two groups with similar means still differ in?

Hint 2 — Tools

to_numeric(), dropna(), sns.boxplot() or Axes.boxplot()

Revisit: Convert numeric text · Drop missing rows · Box plot · Finish a chart properly

Hint 3 — Approach

Retain known numeric durations and compare each depot’s median, middle half and whiskers using the standard 1.5-IQR rule.

Explained solution

Add these lines below # Your work in the editor. The supplied input setup is already there.

work = df.copy()
work['minutes'] = pd.to_numeric(work.minutes, errors='coerce')
observations = work[['depot', 'minutes']].dropna()
fig, ax = plt.subplots()
sns.boxplot(
    data=observations,
    x='depot',
    y='minutes',
    ax=ax,
)
ax.set(title='Delivery duration spread', xlabel='Depot', ylabel='Minutes')
fig.tight_layout()
plt.show()
View supplied setup

This code is already at the top of the editor.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Supplied input: df (24 rows)
df = pd.DataFrame(
    [
        ('D001', 'East', 'Delivered', 32, 1.2, '2026-04-01'),
        ('D002', 'West', 'Delivered', 48, 1.9, '2026-04-01'),
        ('D003', 'North', 'Delivered', 25, 2.6, '2026-04-02'),
        ('D004', 'East', 'Delivered', None, 3.3, '2026-04-02'),
        ('D005', 'West', 'Delivered', 45, 4, '2026-04-03'),
        ('D006', 'North', 'Delivered', 37, 1.2, '2026-04-03'),
        ('D007', 'East', 'Delivered', 72, 1.9, '2026-04-04'),
        ('D008', 'West', 'Delivered', 29, 2.6, '2026-04-04'),
        ('D009', 'North', 'Delivered', 'bad', 3.3, '2026-04-05'),
        ('D010', 'East', 'Delivered', 49, 4, '2026-04-05'),
        ('D011', 'West', 'Delivered', 26, 1.2, '2026-04-06'),
        ('D012', 'North', 'Delivered', 62, 1.9, '2026-04-06'),
        ('D013', 'East', 'Delivered', 46, 2.6, '2026-04-07'),
        ('D014', 'West', 'Delivered', 38, 3.3, '2026-04-07'),
        ('D015', 'North', 'Delivered', 73, 4, '2026-04-08'),
        ('D016', 'East', 'Delivered', 30, 1.2, '2026-04-08'),
        ('D017', 'West', 'Delivered', 34, 1.9, '2026-04-09'),
        ('D018', 'North', 'Delivered', 50, 2.6, '2026-04-09'),
        ('D019', 'East', 'Delivered', 27, 3.3, '2026-04-10'),
        ('D020', 'West', 'Delivered', 63, 4, '2026-04-10'),
        ('D021', 'North', 'Delivered', 47, 1.2, '2026-04-11'),
        ('D022', 'East', 'Delivered', 180, 1.9, '2026-04-11'),
        ('D023', 'West', 'Delivered', 74, 2.6, '2026-04-12'),
        ('D024', 'North', 'Delivered', 31, 3.3, '2026-04-12'),
    ],
    columns=['delivery_id', 'depot', 'status', 'minutes', 'weight_kg', 'date'],
)

Why these steps exist

  • The middle half and whiskers describe spread that a single average hides.
  • The long delivery remains visible as an outlier under the 1.5-IQR rule; unusual is not the same as invalid.

Another valid approach

Matplotlib or Seaborn box plots are accepted with the same group quartiles, 1.5-IQR whiskers and visible outliers.

Tab: indent · Shift+Tab: outdent · Esc, then Tab: leave editor

Edit Python. Control or Command plus Enter runs it. Tab indents by four spaces. Shift plus Tab outdents. Press Escape, then Tab or Shift plus Tab to leave the editor.

Each run executes all editor code in a fresh Python session. Named outputs appear below when you run. Display charts with plt.show().

Python starts when you open a lesson.

Output

Run your code to see what Python returns.