Το παρόν Case Study εξετάζει την κερδοφορία αεροπορικών δρομολογίων. Το Dataset περιλαμβάνει πάνω από 7.500 πτήσεις σε 30 δρομολόγια από το Ντουμπάι (DXB). Κάθε εγγραφή περιέχει στοιχεία λειτουργίας της πτήσης (τύπος αεροσκάφους, επιβάτες, πληρότητα, ώρες πτήσης), οικονομικά δεδομένα εσόδων και αναλυτικές κατηγορίες κόστους (π.χ. καύσιμα, πλήρωμα, συντήρηση). Επιπλέον, παρέχει δείκτες κερδοφορίας και πληροφορίες για τις εποχιακές διακυμάνσεις της ζήτησης. Στόχος είναι η δημιουργία ενός μοντέλου που προβλέπει τα Συνολικά Έσοδα (Total_Revenue).
Χρησιμοποιούμε δύο ξεχωριστά σύνολα δεδομένων:
airline_route_train.csv: Για την εκπαίδευση και διερεύνηση του μοντέλου.
airline_route_test.csv: Για την αξιολόγηση της ικανότητας πρόβλεψης σε νέα δεδομένα.
Ενδεικτικά, μερικές από τις σημαντικότερες μεταβλητές του Dataset είναι:
Load_Factor: Αριθμητική μεταβλητή. Εκφράζει το ποσοστό πληρότητας, με εύρος από 0.50 έως 0.95.
Flight_Hours: Αριθμητική μεταβλητή. Διάρκεια της πτήσης σε ώρες.
Total_Revenue: Αριθμητική μεταβλητή. Το συνολικό έσοδο σε νομισματική μονάδα (π.χ. USD).
Total_Cost: Αριθμητική μεταβλητή. Το συνολικό λειτουργικό κόστος σε νομισματική μονάδα.
Profit_Margin: Αριθμητική μεταβλητή. Το κέρδος ως ποσοστό (%) των συνολικών εσόδων (αρνητικές τιμές υποδηλώνουν ζημία).
Route_Category: Κατηγορική μεταβλητή (Short Haul, Medium Haul, Long Haul).
Aircraft_Type: Κατηγορική μεταβλητή (μοντέλο αεροσκάφους).
Στο πρώτο βήμα, αναλύουμε τις συσχετίσεις και την κατανομή των δεδομένων για να επιλέξουμε τις κατάλληλες ανεξάρτητες μεταβλητές.
train <- read.csv("airline_route_train.csv")
test <- read.csv("airline_route_test.csv")
colnames(train) <- make.names(colnames(train))
colnames(test) <- make.names(colnames(test))
str(train)
## 'data.frame': 6379 obs. of 33 variables:
## $ Flight_Number : chr "EK8960" "EK3960" "EK7529" "EK4543" ...
## $ Flight_Date : chr "20-12-24" "13-05-24" "12-10-24" "25-06-24" ...
## $ Origin : chr "DXB" "DXB" "DXB" "DXB" ...
## $ Destination : chr "ORD" "HYD" "CDG" "DEL" ...
## $ Route : chr "DXB-ORD" "DXB-HYD" "DXB-CDG" "DXB-DEL" ...
## $ Aircraft_Type : chr "Boeing 777-300ER" "Boeing 787-9" "Boeing 787-9" "Boeing 787-9" ...
## $ Aircraft_Capacity : int 396 296 296 296 180 180 296 189 180 296 ...
## $ Passengers : int 308 234 251 229 142 171 281 148 171 281 ...
## $ Load_Factor : num 0.779 0.791 0.85 0.775 0.79 ...
## $ Flight_Hours : num 14.5 4.2 7.5 3.5 2.2 2 5 1.5 2 5 ...
## $ Season : chr "Peak" "Normal" "Shoulder" "Low" ...
## $ Route_Category : chr "Long Haul" "Medium Haul" "Long Haul" "Medium Haul" ...
## $ Demand_Level : chr "Medium" "Medium" "High" "High" ...
## $ Ticket_Revenue : num 410785 145890 602841 126485 32651 ...
## $ Ancillary_Revenue : num 53432 17695 78724 17543 3872 ...
## $ Total_Revenue : num 464217 163585 681565 144028 36523 ...
## $ Fuel_Cost : num 131034 21339 41012 17334 5577 ...
## $ Maintenance_Cost : int 50750 9240 16500 7700 2530 2300 11000 1800 2300 11000 ...
## $ Crew_Cost : int 21750 5040 9000 4200 1716 1560 6000 1200 1560 6000 ...
## $ Depreciation_Cost : int 65250 13440 24000 11200 3740 3400 16000 2700 3400 16000 ...
## $ Insurance_Cost : int 11600 2520 4500 2100 616 560 3000 450 560 3000 ...
## $ Airport_Fees : num 4262 2017 10765 6508 4719 ...
## $ Catering_Cost : num 5186 5851 4134 6509 3361 ...
## $ Handling_Cost : num 4460 5426 3762 4441 3414 ...
## $ Navigation_Fees : num 10637 3027 3432 2080 1662 ...
## $ Sales_Distribution_Cost: num 78194 21586 100189 22687 5134 ...
## $ Passenger_Service_Cost : num 5100 6022 6514 4791 3095 ...
## $ Overhead_Cost : num 88546 17058 31347 15329 8252 ...
## $ Marketing_Cost : num 25884 8821 23695 6795 1493 ...
## $ IT_Systems_Cost : num 3769 1938 3416 2246 1273 ...
## $ Total_Cost : num 506422 123324 282266 113919 46581 ...
## $ Profit : num -42204 40262 399299 30109 -10058 ...
## $ Profit_Margin : num -9.09 24.61 58.59 20.91 -27.54 ...
summary(train$Total_Revenue)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 17311 63123 201647 296499 462645 1496567
# Έλεγχος συσχετίσεων για τις βασικές παραμέτρους
numeric_vars <- train %>% select(Total_Revenue, Passengers, Flight_Hours, Load_Factor, Fuel_Cost, Total_Cost, Profit_Margin)
cor_matrix <- cor(numeric_vars)
corrplot(cor_matrix, method = "number", type = "upper")
Μετά την οπτικοποίηση του πίνακα συσχετίσεων (corrplot), προκύπτουν κρίσιμα συμπεράσματα που καθοδηγούν την επιλογή των μεταβλητών για το μοντέλο παλινδρόμησης:
Έσοδα και Επιβάτες (\(r = 0.80\)): Η ισχυρή θετική συσχέτιση επιβεβαιώνει ότι ο αριθμός των επιβατών αποτελεί τον κύριο προσδιοριστικό παράγοντα (driver) των συνολικών εσόδων. Η τιμή \(0.80\) υποδηλώνει μια πολύ ισχυρή γραμμική σχέση, καθιστώντας τη μεταβλητή Passengers την καταλληλότερη για το αρχικό μοντέλο απλής παλινδρόμησης.
Καύσιμα και Διάρκεια Πτήσης (\(r = 0.89\)): Παρατηρείται εξαιρετικά ισχυρή συσχέτιση μεταξύ των ωρών πτήσης (Flight_Hours) και του συνολικού κόστους (Total_Cost). Αυτό ερμηνεύεται από το γεγονός ότι οι πτήσεις μεγαλύτερης διάρκειας επιβαρύνονται αναλογικά περισσότερο από μεταβλητά έξοδα, με κυριότερο το κόστος καυσίμων (Fuel_Cost), το οποίο επίσης παρουσιάζει υψηλή συνάφεια με τα έσοδα (\(r = 0.98\)).
Σχέση Εσόδων - Κόστους (\(r = 0.88\)): Η πολύ υψηλή συσχέτιση υποδηλώνει ότι η αύξηση της επιχειρησιακής κλίμακας (π.χ. μεγαλύτερα αεροσκάφη ή μακρινότερα δρομολόγια) αυξάνει τα έσοδα, αλλά συνοδεύεται από σχεδόν παράλληλη αύξηση των εξόδων. Αυτό εξηγεί γιατί η πρόβλεψη των εσόδων είναι συχνά πιο “σταθερή” στατιστικά από την πρόβλεψη του καθαρού κέρδους.
Αποδοτικότητα και Load Factor (\(r = 0.42\)): Η μέτρια θετική συσχέτιση μεταξύ του περιθωρίου κέρδους (Profit_Margin) και της πληρότητας (Load_Factor) υποδεικνύει ότι, αν και η γεμάτη καμπίνα συμβάλλει στην κερδοφορία, δεν την εξασφαλίζει από μόνη της. Παράγοντες όπως η τιμολογιακή πολιτική (yield management) και η αποτελεσματική διαχείριση των λειτουργικών εξόδων παίζουν εξίσου σημαντικό ρόλο.Συμπέρασμα για το επόμενο στάδιο:Λαμβάνοντας υπόψη τα παραπάνω, στο Βήμα 2 θα προχωρήσουμε στη δημιουργία ενός μοντέλου που θα περιλαμβάνει τις μεταβλητές με τη μεγαλύτερη ερμηνευτική ισχύ (Passengers, Fuel_Cost και Flight_Hours), ενώ θα εξετάσουμε τη “στιβαρότητα” (robustness) του μοντέλου αφαιρώντας μεταβλητές με χαμηλότερη συσχέτιση όπως ο Load_Factor.
Δημιουργία και Αξιολόγηση ΜοντέλουΘα ακολουθήσουμε τη διαδικασία προσθήκης και αφαίρεσης μεταβλητών για να καταλήξουμε στο βέλτιστο μοντέλο.
Ξεκινάμε με ένα απλό μοντέλο και προσθέτουμε μεταβλητές για να αυξήσουμε το \(R^2\).
# Μοντέλο 1: Απλή Παλινδρόμηση
model1 <- lm(Total_Revenue ~ Passengers, data = train)
summary(model1)
##
## Call:
## lm(formula = Total_Revenue ~ Passengers, data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -646333 -100011 -12036 89015 625574
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -320799.6 6163.0 -52.05 <2e-16 ***
## Passengers 2427.3 22.9 106.01 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 161200 on 6377 degrees of freedom
## Multiple R-squared: 0.638, Adjusted R-squared: 0.6379
## F-statistic: 1.124e+04 on 1 and 6377 DF, p-value: < 2.2e-16
# Υπολογισμός SSE1
SSE1 <- sum(model1$residuals^2)
cat("Sum of Squared Errors (SSE1):", SSE1)
## Sum of Squared Errors (SSE1): 1.656448e+14
# Μοντέλο 2: Πολλαπλή Παλινδρόμηση (Προσθήκη Flight_Hours & Fuel_Cost & Load_Factor)
model2 <- lm(Total_Revenue ~ Passengers + Flight_Hours + Fuel_Cost + Load_Factor, data = train)
summary(model2)
##
## Call:
## lm(formula = Total_Revenue ~ Passengers + Flight_Hours + Fuel_Cost +
## Load_Factor, data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -535486 -82362 -9670 57900 753709
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -4.270e+05 1.678e+04 -25.437 < 2e-16 ***
## Passengers 1.591e+03 3.830e+01 41.529 < 2e-16 ***
## Flight_Hours 1.528e+04 1.111e+03 13.751 < 2e-16 ***
## Fuel_Cost 9.733e-01 1.486e-01 6.550 6.21e-11 ***
## Load_Factor 2.215e+05 2.317e+04 9.559 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 138500 on 6374 degrees of freedom
## Multiple R-squared: 0.7329, Adjusted R-squared: 0.7327
## F-statistic: 4372 on 4 and 6374 DF, p-value: < 2.2e-16
# Υπολογισμός SSE2
SSE2 <- sum(model2$residuals^2)
cat("Sum of Squared Errors (SSE2):", SSE2)
## Sum of Squared Errors (SSE2): 1.222066e+14
ggplot(train, aes(x = Passengers, y = Total_Revenue)) +
geom_point(alpha = 0.3) +
geom_smooth(method = "lm", col = "red") +
labs(title = "Μοντέλο Απλής Γραμμικής Παλινδρόμησης",
x = "Passengers",
y = "Total Revenue")
Σχολιασμός: Το R-squared δείχνει πόσο ποσοστό της διακύμανσης εξηγείται από το μοντέλο. Με \(r=0.80\), αναμένουμε ένα \(R^2 \approx 0.64\).
Εξετάζουμε τα p-values του Μοντέλου 2. Αν κάποια μεταβλητή (π.χ. Load_Factor) δεν είναι σημαντική, την αφαιρούμε για να γίνει το μοντέλο στιβαρό (robust).
# Αφαίρεση του Load_Factor (Backward Elimination)
RobustModel <- lm(Total_Revenue ~ Passengers + Flight_Hours + Fuel_Cost, data = train)
# Υπολογισμός SSE και RMSE για το Robust Model στο Training Set
SSE_train <- sum(RobustModel$residuals^2)
RMSE_train <- sqrt(SSE_train/nrow(train))
cat("SSE (Training):", SSE_train, "\n")
## SSE (Training): 1.239586e+14
cat("RMSE (Training):", RMSE_train, "\n")
## RMSE (Training): 139399.8
cat("Adjusted R-squared (Robust):", summary(RobustModel)$adj.r.squared)
## Adjusted R-squared (Robust): 0.7289456
Σύγκριση: * Αν το SSE2 < SSE1, το μοντέλο με τις δύο μεταβλητές είναι ακριβέστερο.
Το Adjusted R-squared μας επιτρέπει να δούμε αν η προσθήκη της Flight_Hours προσφέρει ουσιαστική πληροφορία.
Χρησιμοποιούμε τη συνάρτηση predict() για να εκτιμήσουμε τα έσοδα μιας μελλοντικής πτήσης.
# Πρόβλεψη
Predictions <- predict(RobustModel, newdata = test)
plot_data <- data.frame(Actual = test$Total_Revenue, Predicted = Predictions)
ggplot(plot_data, aes(x = Actual, y = Predicted)) +
geom_point(color = "darkgreen", alpha = 0.5) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
labs(title = "Πραγματικά vs Προβλεπόμενα Έσοδα (Test Set)")
### Βήμα 4: Διερεύνηση SSE και Out-of-Sample R-squared
#Σύμφωνα με τη θεωρία του μαθήματος, υπολογίζουμε τους δείκτες αξιολόγησης για το Test Set χειροκίνητα.
# 1. Υπολογισμός SSE (Sum of Squared Errors)
SSE_test <- sum((Predictions - test$Total_Revenue)^2)
# 2. Υπολογισμός SST (Total Sum of Squares)
# Χρησιμοποιούμε τη μέση τιμή των εσόδων από το TRAINING SET
SST_test <- sum((mean(train$Total_Revenue) - test$Total_Revenue)^2)
# 3. Υπολογισμός Out-of-Sample R-squared
R2_test <- 1 - (SSE_test / SST_test)
# 4. Υπολογισμός RMSE (Root Mean Square Error)
RMSE_test <- sqrt(SSE_test / nrow(test))
cat("Out-of-Sample R-squared:", R2_test, "\n")
## Out-of-Sample R-squared: 0.7217349
cat("Out-of-Sample RMSE:", RMSE_test)
## Out-of-Sample RMSE: 138196
Απόδοση Μοντέλου: Το μοντέλο πέτυχε ένα Out-of-Sample \(R^2\) ύψους r round(R2_test, 4), το οποίο είναι πολύ κοντά στο \(R^2\) του training set.
Αυτό υποδηλώνει ότι το μοντέλο έχει υψηλή γενικευτική ισχύ και δεν παρουσιάζει φαινόμενα overfitting.
Στιβαρότητα: Η διαδικασία αφαίρεσης μεταβλητών (Backward) έδειξε ότι οι Passengers, Flight_Hours και Fuel_Cost είναι οι βασικοί οδηγοί των εσόδων.
Ο Load_Factor κρίθηκε πλεονασματικός.
Σφάλμα: Το RMSE στο test set (r round(RMSE_test, 2)) είναι ελαφρώς μεγαλύτερο από του training set, γεγονός που αναμενόταν και επιβεβαιώνει την ορθότητα της διαδικασίας.
Το μοντέλο κρίνεται έγκυρο και στιβαρό για τη λήψη επιχειρηματικών αποφάσεων.