All Data Labs

Business analytics

Flight Delay Analysis

medium3–4 hours3 datasets
Company
American Airlines
Job positions
Data AnalystAnalytics EngineerBusiness Analyst
Topics
Root cause analysisWindow functionsTime zonesData cleaningSQL

The scenario

American Airlines: Separate the delay a flight inherits from the delay it creates, and trace the worst delays back to the flights that caused them.

One American Airlines aircraft flies four to six flights a day, one after another, and the schedule leaves it just enough time on the ground between them. So a flight that lands late makes the next one late, and the delay follows that aircraft until a long gap lets it catch up. You're an analyst on the network operations team, which can list the late flights but not say what started them.

Your task

Split every departure delay into what the aircraft inherited and what the airport added, then rank the flights that cost the most minutes to the ones behind them.

Instructions

  1. 1Load and clean the flights. The table arrives unordered, so put them in order by tail number (the aircraft's registration) and then scheduled departure, treating each aircraft's first flight of the day as a fresh start.
  2. 2Join each airport and aircraft type to its minimum turn time, which is the least time that aircraft needs on the ground there before it can fly again.
  3. 3The earliest a flight could leave is the previous flight's actual arrival plus that minimum turn. Its inherited delay is how much later that is than its scheduled departure, and zero when the aircraft was back in time.
  4. 4The created delay is the departure delay minus the inherited delay. Keep its sign, so a flight turned faster than the minimum shows as negative rather than zero.
  5. 5Decide what to do with flights that have no actual times, where the aircraft never went, and explain your choice. Save leg_delays.csv with the columns leg_id, departure_delay_minutes, inherited_delay_minutes and created_delay_minutes.
  6. 6A delay starts at a flight whose created delay is 15 minutes or more and whose inherited delay is under 15. Count the unbroken run of later flights on the same aircraft inheriting 15 or more, and save cascade_roots.csv with the columns leg_id, flight_number, tail_number, origin, scheduled_departure, created_delay_minutes, downstream_legs_affected and downstream_delay_minutes, worst first.
  7. 7Report the airports and local times of day where delays start most often, and say how often the recorded reason agrees with your arithmetic.

Datasets

All files come in one download.

flight_legs.csv

About 11,000 flights from November 3 to November 16, 2025, one row per leg flown, in no particular order. Every timestamp is in UTC.

11,190 rows · 12 columns · 1.3 MB

ColumnTypeDescription
leg_idintegerUnique ID of the flight.
flight_numbertextThe flight number it was flown as.
tail_numbertextThe aircraft that flew it. This is what links one flight to the next.
aircraft_typetextAircraft type, which decides the minimum turn.
origintextAirport it departed from.
destinationtextAirport it arrived at.
scheduled_departuredatetimeScheduled departure, in UTC.
scheduled_arrivaldatetimeScheduled arrival, in UTC.
actual_departuredatetimeActual departure, in UTC. Empty where the flight never went.
actual_arrivaldatetimeActual arrival, in UTC. Empty where the flight never went.
scheduled_block_minutesintegerScheduled time from departure to arrival.
delay_reason_codetextReason recorded by the airport: weather, atc, crew, maintenance, ground_ops or late_inbound_aircraft. Empty on flights that left on time, and not always filled in on those that did not.
Preview the first 5 rows
leg_idflight_numbertail_numberaircraft_typeorigindestinationscheduled_departurescheduled_arrivalactual_departureactual_arrivalscheduled_block_minutesdelay_reason_code
3110087AA2286N449AAA320RDUPHX2025-11-04 17:41:002025-11-04 22:32:002025-11-04 18:04:002025-11-04 23:11:00291ground_ops
3104564AA2163N367AAA320CMHMIA2025-11-16 05:40:002025-11-16 08:28:002025-11-16 05:51:002025-11-16 08:45:00168empty
3103484AA2883N351AAB738MIAOKC2025-11-17 01:52:002025-11-17 05:11:002025-11-17 01:46:002025-11-17 05:02:00199empty
3105697AA1496N384AAE175DCAMCI2025-11-11 19:02:002025-11-11 21:44:002025-11-11 18:58:002025-11-11 21:39:00162empty
3107957AA1956N417AAA320BNADFW2025-11-12 21:21:002025-11-12 23:19:002025-11-12 21:29:002025-11-12 23:27:00118empty

airports.csv

The 24 airports in the two weeks of flying, with the time zone each one keeps.

24 rows · 5 columns · 2 KB

ColumnTypeDescription
airport_codetextThree letter airport code.
airport_nametextFull name of the airport.
citytextCity the airport serves.
timezonetextThe airport's time zone, for converting UTC to local time.
is_hubtextWhether the airport is a hub: yes or no.
Preview the first 5 rows
airport_codeairport_namecitytimezoneis_hub
DFWDallas Fort Worth InternationalDallasAmerica/Chicagoyes
CLTCharlotte Douglas InternationalCharlotteAmerica/New_Yorkyes
ORDChicago OHare InternationalChicagoAmerica/Chicagoyes
MIAMiami InternationalMiamiAmerica/New_Yorkyes
PHXPhoenix Sky Harbor InternationalPhoenixAmerica/Phoenixyes

minimum_turn_times.csv

The least ground time allowed for each aircraft type at each airport.

120 rows · 3 columns · 1 KB

ColumnTypeDescription
airport_codetextThe airport.
aircraft_typetextThe aircraft type.
minimum_turn_minutesintegerMinutes the aircraft needs on the ground before it can fly again.
Preview the first 5 rows
airport_codeaircraft_typeminimum_turn_minutes
DFWA31945
DFWA32045
DFWA32150
DFWB73845
DFWE17535

Hints

Once the flights are in order by aircraft and scheduled departure, the previous flight's actual arrival is the row before it within that aircraft.

legs = legs.sort_values(["tail_number", "scheduled_departure"])
legs["prev_arrival"] = legs.groupby("tail_number")["actual_arrival"].shift(1)

Every timestamp is in UTC. Saying delays start at 13:00 tells an airport nothing, so convert to its own time zone before reporting an hour of the day.

legs["local"] = legs["scheduled_departure"].dt.tz_localize("UTC").dt.tz_convert("America/Chicago")

Deliverable

A public GitHub repo with your analysis (a notebook, scripts or SQL), leg_delays.csv and cascade_roots.csv, and a README with how you built the sequence, your handling of flights that never went, and what you found.

When you're done, post your repo in the Solutions tab to share it with other learners.

What grading checks

Use this checklist to review your own work before you post and share it.

  • Submitted GitHub repo is public and reachable.
  • Repo contains at least one notebook, script or SQL file.
  • leg_delays.csv has one row per flight, with flights that never went left empty rather than counted as on time.
  • The inherited and created split matches the expected values for at least 98 percent of flights that flew, with created delay keeping its sign.
  • The ten worst starting flights in cascade_roots.csv match the expected ten.
  • Flights that never went do not pass a stale arrival to the next flight, and the first flight of each aircraft's day inherits nothing.
  • Times of day are reported in the airport's local time, and the recorded reason is checked against the arithmetic rather than trusted instead of it.