Το παρόν σύνολο δεδομένων αφορά την κερδοφορία 30 αεροπορικών δρομολογίων από το Ντουμπάι (DXB). Περιλαμβάνει περίπου 7500 πτήσεις με 33 μεταβλητές που καλύπτουν επιχειρησιακά στοιχεία (ώρες πτήσης, πληρότητα) και οικονομικά δεδομένα (κόστος καυσίμων, συνολικά έσοδα, περιθώριο κέρδους).
Στόχος μας είναι να ομαδοποιήσουμε τις πτήσεις σε “τύπους δρομολογίων” με βάση την οικονομική τους συμπεριφορά και τα λειτουργικά τους χαρακτηριστικά.
Ενδεικτικά, μερικές από τις σημαντικότερες μεταβλητές του 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: Κατηγορική μεταβλητή (μοντέλο αεροσκάφους).
Θα χρησιμοποιήσουμε τις μεταβλητές: Load_Factor, Flight_Hours, Total_Revenue, Total_Cost, Profit_Margin και Passengers.
# Φόρτωση δεδομένων (airline_route_profitability.csv)
train <- read.csv("airline_route_profitability.csv")
# Επιλογή αριθμητικών μεταβλητών για συσταδοποίηση
airline_numeric <- train %>%
select(Load_Factor, Flight_Hours, Total_Revenue, Total_Cost, Profit_Margin, Passengers)
# Κανονικοποίηση δεδομένων (Scaling)
# Απαραίτητο βήμα γιατί οι τιμές έχουν τεράστιες διαφορές στις κλίμακες (Μετατρέπουμε τις τιμές σε Z-scores, τιμές που δεν εκφράζουν πλέον δολάρια, ώρες ή ποσοστά, αλλά αποστάσεις από τον μέσο όρ)
airline_scaled <- scale(airline_numeric)
# Δείγμα των δεδομένων
head(airline_scaled)## Load_Factor Flight_Hours Total_Revenue Total_Cost Profit_Margin
## [1,] -0.2560497 1.7939601 0.6250400 1.6109616 -0.3913932
## [2,] -0.1204453 -0.4669598 -0.5016277 -0.5841106 0.4718110
## [3,] 0.5541585 0.2574126 1.4395864 0.3265956 1.3421872
## [4,] -0.3050497 -0.6206146 -0.5749208 -0.6379980 0.3770378
## [5,] -0.1307011 -0.9059734 -0.9778157 -1.0238324 -0.8639783
## [6,] 1.6914127 -0.9498747 -0.8797383 -0.9881074 0.2448677
## Passengers
## [1,] 0.60335433
## [2,] -0.23620033
## [3,] -0.04332967
## [4,] -0.29292700
## [5,] -1.27997099
## [6,] -0.95095633
Υπολογίζουμε τις αποστάσεις (Euclidean) και εφαρμόζουμε τη μέθοδο Ward.D2 για να δημιουργήσουμε συμπαγείς ομάδες.
# Υπολογισμός αποστάσεων
distances <- dist(airline_scaled, method = "euclidean")
# Εκτέλεση Ιεραρχικής Συσταδοποίησης
hc_model <- hclust(distances, method = "ward.D2")
# Σχεδίαση Δενδρογράμματος
plot(hc_model, labels = FALSE, main = "Δενδρόγραμμα Πτήσεων (Hierarchical Clustering)", xlab = "Πτήσεις", sub = "")
rect.hclust(hc_model, k = 4, border = "red") # Επιλέγουμε ενδεικτικά 4 clustersΣύμφωνα με τη θεωρία, μπορούμε να διαιρέσουμε το δείγμα σε
περισσότερα clusters (π.χ. 10) και να χρησιμοποιήσουμε εντολές όπως
tapply και colMeans για βαθύτερη ανάλυση.
# Επιλέγουμε 10 clusters όπως προτείνει η θεωρία
clusterGroups = cutree(hc_model, k = 10)
# Χρήση tapply για να βρούμε το μέσο όρο κερδοφορίας και πληρότητας ανά cluster
# Το tapply είναι πολύ χρήσιμο για να δούμε το "προφίλ" κάθε ομάδας
tapply(train$Profit_Margin, clusterGroups, mean)## 1 2 3 4 5 6
## -13.323488 10.817418 41.367002 -2.191982 17.062135 -11.951579
## 7 8 9 10
## 38.918696 33.486387 15.028569 -116.471584
## 1 2 3 4 5 6 7 8
## 0.7235679 0.7677613 0.8510391 0.8712408 0.8788332 0.7122157 0.8967177 0.7365832
## 9 10
## 0.8371241 0.7210416
# Χρήση colMeans για το Cluster 1
# Παίρνουμε τη μέση τιμή κάθε μεταβλητής για τις πτήσεις της πρώτης ομάδας
cat("Μέσοι όροι μεταβλητών για το Cluster 1:\n")## Μέσοι όροι μεταβλητών για το Cluster 1:
## Load_Factor Flight_Hours Total_Revenue Total_Cost Profit_Margin
## 7.235679e-01 1.503694e+01 3.836257e+05 4.194557e+05 -1.332349e+01
## Passengers
## 2.524501e+02
Μπορούμε να δούμε σε ποιο cluster ανήκει μια συγκεκριμένη πτήση. Έστω ότι εξετάζουμε την πτήση στη γραμμή 259:
# Δες σε ποιο cluster ανήκει η πτήση 259
cat("Η πτήση στη γραμμή 259 ανήκει στο Cluster:", clusterGroups[259], "\n")## Η πτήση στη γραμμή 259 ανήκει στο Cluster: 9
# Δημιουργία υποσυνόλου δεδομένων μόνο για το Cluster (9) της πτήσης 257
cluster_subset = subset(train, clusterGroups == clusterGroups[259])
cat("Πρώτα 5 δρομολόγια στο ίδιο Cluster:\n")## Πρώτα 5 δρομολόγια στο ίδιο Cluster:
## [1] "DXB-SYD" "DXB-MEL" "DXB-SYD" "DXB-SYD" "DXB-LAX"
Προσθέτουμε την πληροφορία των clusters στο αρχικό μας dataset για να καταλάβουμε τι αντιπροσωπεύει κάθε ομάδα.
# Προσθήκη του cluster group
train$Cluster <- as.factor(km_res$cluster)
# Σύνοψη των χαρακτηριστικών ανά Cluster
cluster_profile <- train %>%
group_by(Cluster) %>%
summarise(
Count = n(),
Avg_Revenue = mean(Total_Revenue),
Avg_Profit_Margin = mean(Profit_Margin),
Avg_Hours = mean(Flight_Hours),
Avg_Load = mean(Load_Factor)
)
print(cluster_profile)## # A tibble: 4 × 6
## Cluster Count Avg_Revenue Avg_Profit_Margin Avg_Hours Avg_Load
## <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 3083 173650. 19.6 3.75 0.844
## 2 2 1932 68263. -35.3 3.11 0.724
## 3 3 1545 708548. 35.2 9.33 0.869
## 4 4 1414 431262. 1.85 13.1 0.741
Η μέθοδος K-means είναι πιο αποδοτική για μεγάλα σύνολα δεδομένων όπως το δικό μας (6.000+ εγγραφές).
set.seed(160)
# Επιλογή 4 clusters
km_res <- kmeans(airline_scaled, centers = 4, nstart = 25)
# Οπτικοποίηση των clusters
fviz_cluster(km_res, data = airline_scaled,
geom = "point",
ellipse.type = "convex",
ggtheme = theme_minimal(),
main = "Οπτικοποίηση Clusters (K-means)")Dim1 (58.7%): Αυτός ο άξονας μεταφέρει το 58.7% της πληροφορίας. Aντιπροσωπεύει το μέγεθος της πτήσης (Έσοδα, Ώρες, Επιβάτες). Όσο πιο δεξιά είναι μια τελεία, τόσο μεγαλύτερη/μακρύτερη είναι η πτήση.
Dim2 (23%): Μεταφέρει το 23% της πληροφορίας και σχετίζεται με την αποδοτικότητα (Load Factor, Profit Margin).
Cluster 2 (Πράσινο - Αριστερά): Βρίσκεται πολύ αριστερά στον Dim1. Αυτές είναι οι μικρές πτήσεις (Short-haul) με χαμηλά έσοδα. Επειδή είναι στενό και μακρόστενο, δείχνει μεγάλη ομοιομορφία.
Cluster 1 (Κόκκινο - Πάνω αριστερά): Είναι οι μεσαίες πτήσεις. Παρατήρησε ότι συνορεύει με το πράσινο, άρα κάποια δρομολόγια είναι οριακά μεταξύ μικρών και μεσαίων.
Cluster 3 (Γαλάζιο - Δεξιά): Αυτές είναι οι “ναυαρχίδες” σου (Long-haul). Είναι πολύ δεξιά στον Dim1, που σημαίνει μέγιστα έσοδα και πολλές ώρες πτήσης. Το γεγονός ότι η ομάδα είναι “πλατιά” δείχνει ότι οι μεγάλες πτήσεις έχουν μεγαλύτερη ποικιλία μεταξύ τους.
Cluster 4 (Μοβ - Κάτω): Αυτές είναι οι πτήσεις με ιδιαίτερα χαρακτηριστικά, πιθανώς αυτές που έχουν καλή απόδοση αλλά σε μεσαίες αποστάσεις.
Με βάση την ανάλυση των μέσων όρων ανά cluster, μπορούμε να ταυτοποιήσουμε τις εξής ομάδες (ενδεικτικά):
Cluster 1 (Standard Δρομολόγια): Η “ραχοκοκαλιά” της εταιρείας. Μεσαία δρομολόγια με σταθερή κερδοφορία (19.6%).
Cluster 2 (Προβληματικά Δρομολόγια): SOS. Χαμηλή πληρότητα και σημαντική ζημία (-35.3%). Χρήζουν άμεσης επαναξιολόγησης.
Cluster 3 (Ναυαρχίδες - Long Haul): Οι πιο αποδοτικές πτήσεις. Υψηλά έσοδα και μέγιστο κέρδος (35.2%).
Cluster 4 (Μακρινές Διαδρομές Χαμηλής Απόδοσης): Πολύ μεγάλες πτήσεις (13 ώρες) που “παλεύουν” με οριακό κέρδος λόγω υψηλού κόστους καυσίμων.
Η συσταδοποίηση μας επέτρεψε να ομαδοποιήσουμε 7.500 πτήσεις σε διακριτές κατηγορίες. Η χρήση των tapply και colMeans επιβεβαίωσε ότι η πραγματική κερδοφορία εξαρτάται περισσότερο από το Load_Factor παρά από τα συνολικά έσοδα.