swadhinbiswas style: apply ruff formatting · 8/1/2026
706e694
263 lines · 7.2 KB
Raw Download

« Back to Index

Delay Types

Why Classification Matters

Not all delays are equal. Classifying delay types enables:

  • Root cause analysis: Pinpoint systemic issues
  • Accountability: Weather delays ≠ airline operational failures
  • Mitigation: Airlines can fix controllable delays, can't fix weather
  • Regulatory compliance: EU261 compensation depends on delay cause

Primary Delay Categories

1. Weather Delays (Code: WEATHER)

Cause: Thunderstorms, snow, fog, high winds, extreme temperatures
Controllable: No
Regulatory treatment: "Extraordinary circumstances" (no compensation required in EU)

Detection in data:

-- Flight delayed AND weather was adverse at departure airport
WHERE delay_minutes > 15 AND is_adverse = TRUE

2. Air Carrier Delays (Code: CARRIER)

Cause: Aircraft cleaning, catering, baggage loading, fueling, crew availability
Controllable: Yes (within airline's operational control)
Regulatory treatment: Compensable in EU (EU261 applies)

Examples:

  • Late crew arrival from previous flight
  • Aircraft maintenance not completed on time
  • Baggage loading delays
  • Late catering truck

3. Late Aircraft Arrival (Code: LATE_AIRCRAFT)

Cause: Incoming aircraft arrived late → cascading delay on next flight
Controllable: Partially (airline schedule padding decision)

Significance: Most common delay type (~35–40% of all delays). Tight turnarounds amplify.

4. National Aviation System (NAS) (Code: NAS)

Cause: ATC restrictions, airport congestion, airspace closures
Controllable: No (government/infrastructure issue)

Examples:

  • Ground delay programs (GDPs)
  • Airspace Flow Programs (AFPs)
  • Airport arrival rate reduced due to volume
  • ATC staffing shortages

5. Security Delays (Code: SECURITY)

Cause: Security checkpoint lines, terminal evacuation, bomb threats
Controllable: No (external)

6. Passenger Delays (Code: PASSENGER)

Cause: Late passengers, missing passengers, gate disputes
Controllable: Partially (airline can choose to offload and depart)

FAA Delay Coding Standard

FAA assigns delay codes to every US flight:

Category FAA Code Weight
Air Carrier 1 35–40%
Late Arriving Aircraft 2 35–40%
NAS 3 15–25%
Weather 4 5–15%
Security 5 <1%
Other/Unknown 0 <1%

Note: In the FAA system, a flight can have multiple delay causes assigned. The primary cause is the biggest contributor.

EU Delay Classification (EU261/2004)

European regulation is passenger-centric. Key rules:

Delay Duration Distance Compensation
3+ hours < 1,500 km €250
3+ hours 1,500–3,500 km €400
3–4 hours > 3,500 km €300
4+ hours > 3,500 km €600

Exception: "Extraordinary circumstances" (weather, ATC strikes, security) = no compensation.

Approach for This Project

Since raw data rarely includes delay cause codes (FAA proprietary), we use derived classification:

def classify_delay(flight, weather) -> str:
    """
    Heuristic delay classification based on available data.
    """
    if flight["status"] == "C":
        return "CANCELLED"

    if flight["delay_minutes"] <= 0:
        return "ON_TIME"  # or early

    # Weather delay: adverse weather at departure
    if weather["is_adverse"] == True:
        return "WEATHER"

    # Carrier delay: no weather, significant delay
    if flight["delay_minutes"] > 30:
        return "CARRIER"

    # Minor operational delays
    return "OPERATIONAL"

Delay Distribution Analysis

In Gold layer delay_analysis:

CREATE OR REPLACE VIEW gold.delay_distribution AS
SELECT
    delay_category,
    COUNT(*) AS flight_count,
    ROUND(AVG(delay_minutes), 1) AS avg_delay,
    ROUND(SUM(delay_minutes) / 60.0, 1) AS total_delay_hours,
    ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 1) AS pct_of_delays
FROM fact_delays
GROUP BY delay_category
ORDER BY flight_count DESC;

Delay Metrics by Airport

-- Airports with worst departure delays
SELECT
    da.airport_code,
    da.airport_name,
    COUNT(*) AS departing_flights,
    ROUND(AVG(ff.delay_minutes), 1) AS avg_departure_delay,
    ROUND(PERCENTILE_CONT(0.99) WITHIN GROUP (ORDER BY ff.delay_minutes), 1) AS p99_delay
FROM fact_flights ff
JOIN dim_airport da ON ff.departure_airport_key = da.airport_key
WHERE ff.delay_minutes > 0
GROUP BY da.airport_code, da.airport_name
HAVING COUNT(*) > 100
ORDER BY avg_departure_delay DESC
LIMIT 20;

Delay Cascading (LATE_AIRCRAFT)

A single delay can cascade across multiple subsequent flights:

Flight AA100 (JFK→LAX) delayed 45 min (weather)

↓ causes

Flight AA100 (LAX→SFO) delayed 30 min (late aircraft)

↓ causes

Flight AA100 (SFO→SEA) delayed 15 min (late aircraft)

Impact: One weather event → 3 delayed flights, affecting 500+ passengers.

To detect cascades in the Gold layer:

SELECT
    aircraft_registration,
    scheduled_departure,
    actual_departure,
    delay_minutes,
    LAG(delay_minutes) OVER (
        PARTITION BY aircraft_registration
        ORDER BY scheduled_departure
    ) AS previous_flight_delay
FROM fact_flights;

Delay Cost Estimation

For business impact analysis, approximate cost:

Delay Duration Estimated Cost per Flight
< 15 min $0 (within buffer)
15–60 min $500–$2,000 (crew overtime, fuel)
1–3 hours $5,000–$15,000 (passenger rebooking, crew duty)
> 3 hours $25,000–$150,000 (EU261 compensation, hotel, full disruption)
-- Estimate total delay cost
SELECT
    CASE
        WHEN delay_minutes <= 15 THEN '$0'
        WHEN delay_minutes <= 60 THEN '$500–$2,000'
        WHEN delay_minutes <= 180 THEN '$5,000–$15,000'
        ELSE '$25,000+'
    END AS cost_bracket,
    COUNT(*) AS flights,
    SUM(delay_minutes) AS total_delay_minutes
FROM fact_flights
WHERE delay_minutes > 0
GROUP BY
    CASE
        WHEN delay_minutes <= 15 THEN '$0'
        WHEN delay_minutes <= 60 THEN '$500–$2,000'
        WHEN delay_minutes <= 180 THEN '$5,000–$15,000'
        ELSE '$25,000+'
    END;

Data Quality Validation: Delays

# Polars validation rules for flight delays
validation_rules = [
    (pl.col("delay_minutes") >= 0, "Negative delay"),
    (pl.col("delay_minutes") <= 1440, "Delay > 24 hours (unrealistic)"),
    (
        pl.col("actual_departure") > pl.col("scheduled_departure"),
        "Early departure with positive delay — inconsistent",
    ),
]

How Delay Data Appears in Warehouse

fact_flights stores the raw delay minutes.
fact_delays stores delay category breakdowns (one flight can have multiple delay reasons).

-- fact_delays structure
SELECT
    flight_key,
    delay_reason AS category,  -- 'WEATHER', 'CARRIER', 'NAS', 'LATE_AIRCRAFT'
    delay_minutes AS category_minutes
FROM fact_delays;

This allows analysis queries like: "How many minutes of delay were caused by weather in 2024?"

SELECT SUM(category_minutes) / 60.0 AS total_weather_delay_hours
FROM fact_delays
WHERE delay_reason = 'WEATHER';

« Back to Index