Q vs Conditional Forecasting¶
There are two different approaches to forecasting the priceable (i.e. price sensitive) demand for unrestricted networks: Q forecasting, and conditional forecasting.
Under Q forecasting, each priceable booking is converted into an equivalent number of Q-class bookings, where the "Q" class is the lowest possible fare class for the relevant path. Forecasts are then made for how much demand there would be for that Q class, and then those forecasts are broadcast up to the various higher fare classes, based on the sellup probability in each time frame along the booking curve.
Under conditional forecasting, bookings are all recorded in the class where they occur, and the level of demand in that class is computed conditional on it being the lowest available fare class at that time.
These two methodologies are similar, and indeed with certain configurations and under the right conditions (e.g. flights never sell out, the lowest available fare class is always the same for full time frames) the methodologies become identical. In practice, and in most simulations, these particular conditions do not actually hold, so these algorithms are not actually identical, so PassengerSim allows you to choose one or the other as appropriate.
import numpy as np
import pandas as pd
import passengersim as pax
pax.versions()
passengersim 0.62 passengersim.core 0.62
cfg = pax.Config.from_yaml(pax.demo_network("3MKT/DEMO"))
In this example, we will work with a completely fenceless marketplace. To convert the typical 3MKT network into a restriction-free network, we can use a tool to strip the restrictions.
from passengersim.config.manipulate import strip_ap_restrictions, strip_fare_restrictions
cfg = strip_fare_restrictions(strip_ap_restrictions(cfg))
For this example, we will assign Q forecasting to AL1. The "Q" RM system uses Q forecasting, as well as a ProBP optimizer. We also need to give this carrier a Frat5 curve, and tell it that we need to store the Q history while running the simulation.
cfg.carriers.AL1.rm_system = "Q" # Q forecasting
cfg.carriers.AL1.frat5 = "curve_C"
cfg.carriers.AL1.store_q_history = True
For AL2, we will use conditional forecasting. We'll select the "M" system, which pairs the conditional forecast with a ProBP optimizer.
cfg.carriers.AL2.rm_system = "M" # Conditional forecasting
cfg.carriers.AL2.frat5 = "curve_C"
sim = pax.MultiSimulation(cfg)
summary = sim.run()
summary.fig_carrier_revenues()
summary.fig_carrier_load_factors()
summary.fig_carrier_rasm()
summary.fig_fare_class_mix()
summary.fig_carrier_head_to_head_revenue("AL1", "AL2")
Without Priceable Detruncation¶
We can remove the detruncation of priceable demand from the Q system, and re-evaluate to see the difference, which is not much.
cfg2 = cfg.model_copy(deep=True)
cfg2.carriers.AL1.rm_system_options = {
"priceable_detruncation": "none",
}
summary2 = pax.MultiSimulation(cfg2).run()
summary2.fig_carrier_revenues()
summary2.fig_carrier_load_factors()
summary2.fig_carrier_rasm()
summary2.fig_fare_class_mix()
summary2.fig_carrier_head_to_head_revenue("AL1", "AL2")