Data Challenge - Πρόβλεψη Πληρότητας Πτήσεων

Στα πλαίσια της εργασίας του μαθήματος Εξόρυξη Γνώσης από Βάσεις Δεδομένων και τον Παγκόσμιο Ιστό, θα δουλέψετε πάνω σε ένα πρόβλημα κατηγοριοποίησης. Συγκεκριμένα, σας δίνεται ένα σύνολο δεδομένων το οποίο αποτελείται από μερικές χιλιάδες πτήσεις, όπου κάθε πτήση περιγράφεται απο ένα σύνολο μεταβλητών (αεροδρόμιο αναχώρησης, αεροδρόμιο άφιξης, κτλ). Κάθε πτήση χαρακτηρίζεται επίσης από μια μεταβλητη που σχετίζεται με τον αριθμό των επιβατών της πτήσης (π.χ. κάθε τιμή της μεταβλητής σχετίζεται με ενα εύρος πλήθους επιβατών). Για κάποιες πτήσεις, η τιμή της μεταβλητής είναι γνωστή, ενώ για άλλες όχι. Στόχος σας είναι να προβλέψετε την τιμη της μεταβλητη για τις πτήσεις για τις οποίες δεν είναι διαθέσιμη.

Σύνολο Δεδομένων

Για να αποκτήσετε πρόσβαση στο σύνολο δεδομένων, θα πρέπει πρώτα να πάτε στη σελίδα http://195.251.252.9/challengeUndergrad/index.php και να δημιουργήστε ένα λογαριασμό. Αφού δημιουργήσετε τον προσωπικό σας λογαριασμό και συνδεθείτε, μπορείτε πλέον από την κεντρική οθόνη να κατεβάσετε το σύνολο δεδομένων (193 KB). Το αρχείο που θα κατεβάσετε είναι συμπιεσμένο και θα πρέπει να το αποσυμπιέσετε. Αφού το αποσυμπιέσετε, θα δείτε ότι αποτελείται από δυο αρχεία. Το αρχείο με όνομα train.csv περιέχει τα δεδομένα εκπαίδευσης (training set) του προβλήματος, ενώ το αρχείο test.csv περιέχει τα δεδομένα ελέγχου (test set) του προβλήματος. Κάθε γραμμή των δυο αυτών αρχείων αντιστοιχεί σε μια πτήση η οποία χαρακτηρίζεται από τις εξής μεταβλητές:

Μεταβλητή Περιγραφή
DateOfDeparture Ημερομηνία αναχώρησης
Departure Κωδικός αεροδρομίου αναχώρησης
CityDeparture Πόλη αναχώρησης
LongitudeDeparture Γεωγραφικό μήκος αεροδρομίου αναχώρησης
LatitudeDeparture Γεωγραφικό πλάτος αεροδρομίου αναχώρησης
Arrival Κωδικός αεροδρομίου άφιξης
CityArrival Πόλη άφιξης
LongitudeArrival Γεωγραφικό μήκος αεροδρομίου άφιξης
LatitudeArrival Γεωγραφικό πλάτος αεροδρομίου άφιξης
WeeksToDeparture Πόσες εβδομάδες πριν την αναχώρηση της πτήσης κατά μέσο όρο κλείσαν οι επιβάτες τα εισητήριά τους
std_wtd Τυπική απόκλιση για το παραπάνω

Το training set περιέχει μια επιπλέον μεταβλητή (PAX) η οποία έχει σχέση με τον αριθμό των επιβατών της πτήσης. Η μεταβλητή αυτή παίρνει 8 διαφορετικές τιμές (τιμές από 0 έως 7 οπότε 8 κατηγορίες συνολικά). Κάθε κατηγορία υποδηλώνει πόσοι περίπου επιβάτες χρησιμοποίησαν την πτήση. Οι αριθμοί στις κατηγορίες έχουν ανατεθεί με τυχαίο τρόπο, οπότε μην θεωρήσετε ότι η κατηγορία 0 υποδηλώνει πολύ λίγους επιβάτες ενώ η κατηγορία 7 πάρα πολλούς επιβάτες. Η μεταβλητή PAX λείπει από το test set καθώς πρόκειται για την μεταβλητή που πρέπει να προβλέψετε στα πλαίσια της παρούσας εργασίας.

Παρακάτω σας δίνεται κώδικας ο οποίος φορτώνει τα δεδομένα εκπαίδευσης σε ένα DataFrame της βιβλιοθήκης Pandas και τυπώνει τις πρώτες 5 γραμμές. Οπότε μπορείτε να δείτε τις 12 μεταβλητές του προβλήματος.

In [1]:
import pandas as pd

df_train = pd.read_csv('dataset/train.csv')
df_train.head()
Out[1]:
DateOfDeparture Departure CityDeparture LongitudeDeparture LatitudeDeparture Arrival CityArrival LongitudeArrival LatitudeArrival WeeksToDeparture std_wtd PAX
0 2011-12-05 ORD Chicago 41.978603 -87.904842 EWR Newark 40.692500 -74.168667 8.352941 5.667243 7
1 2013-03-01 ATL Atlanta 33.636719 -84.428067 LGA New York 40.777245 -73.872608 10.421053 10.001754 7
2 2012-02-06 ORD Chicago 41.978603 -87.904842 BOS Boston 42.364347 -71.005181 9.250000 7.136821 7
3 2012-12-10 ORD Chicago 41.978603 -87.904842 SFO San Francisco 37.618972 -122.374889 8.666667 7.404291 7
4 2012-04-13 SFO San Francisco 37.618972 -122.374889 JFK New York 40.639751 -73.778925 14.037037 9.858544 7

Επίσης, όσον αφορά τις διαστάσεις του training set, όπως βλέπετε παρακάτω, αποτελείται από 8899 γραμμές και 12 στήλες.

In [2]:
df_train.shape
Out[2]:
(8899, 12)

Δηλαδή έχετε διαθέσιμα τα δεδομένα απο 8899 πτήσεις για τις οποίες ξέρετε την κατηγορία του αριθμού επιβάτών PAX.

Αντίθετα, το αρχείο με όνομα test.csv περιέχει το test set του προβλήματος. Όπως και στην περίπτωση του training set, σας δίνεται και τώρα κώδικας ο οποίος φορτώνει το test set σε ένα DataFrame της βιβλιοθήκης Pandas και τυπώνει τις πρώτες 5 γραμμές του.

In [3]:
df_test = pd.read_csv('dataset/test.csv')
df_test.head()
Out[3]:
DateOfDeparture Departure CityDeparture LongitudeDeparture LatitudeDeparture Arrival CityArrival LongitudeArrival LatitudeArrival WeeksToDeparture std_wtd
0 2012-10-21 DFW Dallas-Fort Worth 32.896828 -97.037997 SFO San Francisco 37.618972 -122.374889 14.600000 11.575837
1 2012-09-13 LAX Los Angeles 33.942536 -118.408075 ATL Atlanta 33.636719 -84.428067 14.730769 13.364304
2 2012-09-04 ORD Chicago 41.978603 -87.904842 IAH Houston 29.984433 -95.341442 8.470588 5.885551
3 2012-08-13 DEN Denver 39.861656 -104.673178 PHX Phoenix 33.434278 -112.011583 8.200000 6.292853
4 2012-09-10 ORD Chicago 41.978603 -87.904842 SEA Seattle 47.449000 -122.309306 12.090909 9.138662

Όσον αφορά τις διαστάσεις του test set, όπως βλέπετε παρακάτω, αποτελείται από 2229 γραμμές και 11 στήλες. Η στήλη που λείπει πρόκειται για τη μεταβλητή PAX την οποία στόχος σας είναι να προβλέψετε.

In [4]:
df_test.shape
Out[4]:
(2229, 11)

Στόχος

Όπως αναφέρθηκε και παραπάνω, στόχος σας είναι να προβλέψετε την κατηγορία αριθμού επιβατών (μεταβλητή PAX) για κάθε πτήση του test set. Πρόκειται για ένα supervised learning πρόβλημα. Θα πρέπει να επεξεργαστείτε τα δεδομένα του training set και στη συνέχεια, θα τα χρησιμοποιήσετε για να εκπαιδεύσετε κάποιο ταξινομητή, τον οποίο θα χρησιμοποιήσετε για να κάνετε προβλέψεις σχετικά με τα δεδομένα του test set.

Αξιολόγηση

Η αξιολόγηση των προβλέψεων θα γίνει με βάση το macro F1-score. Το macro F1-score παίρνει τιμές μεταξύ 0 και 1. Όσο μεγαλύτερη η τιμή του F1-score, τόσο καλύτερος ο ταξινομητής που παρήγαγε τις προβλέψεις. Για κάθε μια από τις 8 κατηγορίες του test set μας, ο ταξινομητής θα κάνει κάποιες σωστές προβλέψεις και κάποιες λάθος. Πιο συγκεκριμένα, για μια κατηγορία $c$:

  • τα παραδείγματα που ανήκουν στην κατηγορία $c$ και ο ταξινομητής προέβλεψε ότι πράγματι ανήκουν στην κατηγορία $c$ ονομάζονται True Positives (TP).
  • τα παραδείγματα που ανήκουν στην κατηγορία $c$ και ο ταξινομητής προέβλεψε λανθασμένως ότι ανήκουν σε κάποια άλλη κατηγορία ονομάζονται False Positives (FP).
  • τα παραδείγματα που ανήκουν σε κάποια κατηγορία διαφορετική της $c$ και ο ταξινομητής προέβλεψε ότι πράγματι ανήκουν σε κάποια κατηγορία διαφορετική της $c$ ονομάζονται True Negatives (TN).
  • τα παραδείγματα που ανήκουν σε κατηγορία διαφορετική της $c$ και ο ταξινομητής προέβλεψε ότι ανήκουν στην κατηγορία $c$ ονομάζονται False Negatives (FN).

Δεδομένων των παραπάνω ορισμών, μπορούμε συνήθως να υπολογίσουμε για την κατηγορία $c$ μερικές μετρικές απόδοσης του ταξινομητή μας. Πρώτα, το Recall το οποίο ορίζεται ως: $$ Recall = \frac{TP}{TP+FN} $$ και μεράει το ποσοστό των παραδειγμάτων που προβλέφτηκαν ότι ανήκουν στην κατηγορία $c$ σε σχέση με αυτά που ανήκουν πράγματι στην κατηγορία $c$. Έπειτα, το Precision το οποίο μας λέει πόσα από τα παραδείγματα που προβλέφτηκαν ότι ανήκουν στην κατηγορία $c$, ανήκουν πράγματι σε αυτή την κατηγορία, και ορίζεται ως εξης: $$ Precision = \frac{TP}{TP+FP} $$ Το F1-score ειναι ο αρμονικός μέσος του Precision και του Recall, και ορίζεται ως εξής: $$ F1-score = \frac{2*Recall*Precision}{Recall + Precision} $$ Πρόκειται για μια ευρέως διαδεδομένη μετρική απόδοσης η οποία είναι και αξιόπιστη δεδομένου ότι λαμβάνει υπόψη τόσο τα False Positives και τα False Negatives.

Στο πρόβλημα που σας έχει ανατεθεί υπάρχουν συνολικά 8 κατηγορίες $c_1, c_2, \ldots, c_8$ οπότε μπορούμε να υπολογίσουμε ένα F1-score για κάθε κατηγορία. Το macro F1-score ορίζεται ως ο μέσος όρος των F1-scores όλων των κατηγοριών: $$ macro\text{ }F1-score = \frac{F1-score_{c_1}+F1-score_{c_2}+\ldots+F1-score_{c_8}}{8} $$ όπου $F1-score_{c_i}$ είναι το F1-score για την κατηγορία $i$. Αφότου υποβάλετε μια λύση στην πλατφόρμα (όπως περιγράφεται παρακάτω), το macro F1-score της λύσης σας υπολογίζεται αυτόματα και εμφανίζεται στην οθόνη.

Υποβολή Λύσης

Αφότου έχετε σχεδιάσει και τρέξει τον αλγοριθμό σας, και έχετε προβλέψει την κατηγορία επιβατών για κάθε πτήση του test set, πρέπει να υποβάλετε την λύση σας στην πλατφόρμα ώστε να αξιολογηθεί. Συγκεκριμένα, στην κεντρική οθόνη υπάρχει η επιλογή Submit new file η οποία σας δίνει τη δυνατότητα να ανεβάσετε τις προβλέψεις σας. Οι προβλέψεις σας θα πρέπει να συμπεριληφθούν σε ένα αρχείο όπου κάθε γραμμή περιέχει την πρόβλεψή σας για την πτήση η οποία βρίσκεται στην ίδια γραμμή του test set. Για παράδειγμα, παρακάτω σας δίνονται οι τρείς πρώτες πτήσεις του test set:

2012-10-21,DFW,Dallas-Fort Worth,32.896828,-97.037997,SFO,San Francisco,37.618972,-122.374889,14.6,11.5758369028
2012-09-13,LAX,Los Angeles,33.942536,-118.408075,ATL,Atlanta,33.636719,-84.428067,14.7307692308,13.3643037748
2012-09-04,ORD,Chicago,41.978603,-87.904842,IAH,Houston,29.984433,-95.341442,8.47058823529,5.88555060146

Η πρώτη γραμμή του αρχείου που θα υποβάλετε θα πρέπει να περιέχει την πρόβλεψή σας για την κατηγορία αριθμού επιβατών της πρώτης πτήσης, η δεύτερη γραμμή θα πρέπει να περιέχει την πρόβλεψή σας για την δεύτερη πτήση και αντίστοιχα η τρίτη γραμμή θα πρέπει να περιέχει την πρόβλεψή σας για την τρίτη πτήση. Προσοχή: Στο αρχείο που θα υποβάλετε, κάθε γραμμή θα πρέπει να περιέχει έναν μόνο αριθμό που υποδηλώνει την κατηγορία επιβατών (αριθμοί 0-8). Επιπλέον, θα πρέπει να υπάρχουν συνολικά 2229 γραμμές όσες και οι πτήσεις για τις οποίες πρέπει να κάνετε πρόβλεψη. Η κατάληξη του αρχείου θα πρέπει να είναι .txt . Τέλος, η κωδικοποίηση του αρχείου θα πρέπει να είναι utf-8.

Αρχικός Κώδικας Python

Σας δίνεται ένας αρχικός Python κώδικας ο οποίος χρησιμοποιεί ως μόνη πληροφορία το αεροδρόμιο από το οποίο αναχώρησε η πτήση και το αεροδρόμιο στο οποίο προσγειώθηκε για να προβλέψει την κατηγορία αριθμού επιβατών. Συγκεκριμένα, ο παρακάτω κώδικας αποθηκεύει στη μεταβλητή y_train τη στήλη PAX του training set, δηλαδή την στήλη την οποία θέλουμε να μάθουμε να προβλέπουμε. Στη συνέχεια, διαγράφει όλες τις στήλες του training set εκτός από τις Departure και Arrival οι οποίες αντιστοιχούν στους κωδικούς αεροδρομίων αναχώρησης και άφιξης.

In [5]:
y_train = df_train.as_matrix(['PAX'])
df_train.drop(df_train.columns[[0,2,3,4,6,7,8,9,10,11]], axis=1, inplace=True)

df_train.head()
Out[5]:
Departure Arrival
0 ORD EWR
1 ATL LGA
2 ORD BOS
3 ORD SFO
4 SFO JFK

Για να μπορεί να δουλέψει ένα αλγόριθμος ταξινόμησης είναι απαραίτητο το training και το test set να έχουν ακριβώς τον ίδιο αριθμό στηλών (ίδιες μεταβλητές). Συνεπώς, πρέπει και στο test set να διαγράψουμε όλες τις στήλες εκτός από τις Departure και Arrival. Αυτό γίνεται με τον παρακάτω κώδικα.

In [6]:
df_test.drop(df_test.columns[[0,2,3,4,6,7,8,9,10]], axis=1, inplace=True)

df_test.head()
Out[6]:
Departure Arrival
0 DFW SFO
1 LAX ATL
2 ORD IAH
3 DEN PHX
4 ORD SEA

Οι στήλες των training και test set περιέχουν κατηγορικές μεταβλητές των οποίων οι τιμές είναι αλφαριθμητικά. Οι αλγόριθμοι ταξινόμησης ωστόσο δουλεύουν μονο με αριθμητικές τιμές. Χρησιμοποιούμε το ανικείμενο LabelEncoder του scikit-learn για να μετατρέψουμε τα αλφαριθμητικά σε αριθμητικές τιμές.

In [7]:
from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
le.fit(df_train['Departure'])
df_train['Departure'] = le.transform(df_train['Departure'])
df_train['Arrival'] = le.transform(df_train['Arrival'])
df_test['Departure'] = le.transform(df_test['Departure'])
df_test['Arrival'] = le.transform(df_test['Arrival'])

Έπειτα, εκπαιδεύουμε έναν ταξινομητή logistic regression για να προβλέψουμε τις κατηγορίες αριθμού επιβατών των δεδομένων ελέγχου. Επιπλέον, αποθηκεύουμε τις προβλέψεις μας στο αρχείο y_pred.txt στο δίσκο.

In [8]:
from sklearn.linear_model import LogisticRegression
import numpy as np
import codecs

X_train = df_train.as_matrix()
X_test = df_test.as_matrix()

clf = LogisticRegression()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

with codecs.open('y_pred.txt', 'w', encoding='utf-8') as f:
    for i in range(y_pred.shape[0]):
        f.write(unicode(y_pred[i])+'\n')
/Applications/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py:526: DataConversionWarning: A column-vector y was passed when a 1d array was expected. Please change the shape of y to (n_samples, ), for example using ravel().
  y = column_or_1d(y, warn=True)

Υποβάλλουμε το αρχείο y_pred.txt στην πλατφόρμα και μας δίνει macro F1-score ίσο με 0.05.

Ένας εναλλακτικός τρόπος αναπαράστασης κατηγορικών μεταβλητών είναι το λεγόμενο one-hot encoding όπου υπάρχει διαθέσιμη μια μεταβλητή για κάθε πιθανή τιμή του χαρακτηριστικού και ανάλογα με την τρέχουσα τιμή του, μια από αυτές της μεταβλητές είναι 1, ενώ όλες οι άλλες παραμένουν 0. Για παράδειγμα, αν είχαμε κάποια μεταβλητή Weekday η οποία περιέγραφε τη μέρα που έγινε μια πτήση, θα είχαμε 7 μεταβλητές (π.χ. 1000000 για Monday, 0100000 για Tuesday κτλ.). Σημειώστε ότι με την one-hot encoding αναπαράσταση ο αριθμός των χαρακτηριστικών που προκύπτει είναι ίσος με τον αριθμό των διαφορετικών τιμών που παίρνει η μεταβλητή. Παρακάτω εφαρμόζουμε one-hot encoding στις μεταβλητές Departure και Arrival.

In [9]:
from sklearn.preprocessing import OneHotEncoder

enc = OneHotEncoder(sparse=False)
enc.fit(df_train)  
X_train = enc.transform(df_train)
X_test = enc.transform(df_test)

print X_train.shape
print X_test.shape
(8899, 40)
(2229, 40)

Βλέπουμε ότι ο αριθμός των στηλών αυξήθηκε από 2 σε 40. Αυτό συνέβη γιατί υπάρχουν 20 διαφορετικά αεροδρόμια και συνεπώς χρειαζόμαστε 20 μεταβλητές για να αναπαραστήσουμε κάθε μια από τις μεταβλητές Departure και Arrival χρησιμοποιώντας one-hot encoding.

Έπειτα, εκπαιδεύουμε ξανά έναν ταξινομητή logistic regression για να προβλέψουμε τις κατηγορίες αριθμού επιβατών των δεδομένων ελέγχου. Επιπλέον, αποθηκεύουμε τις προβλέψεις μας στο αρχείο y_pred.txt στο δίσκο.

In [10]:
clf = LogisticRegression()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)

with codecs.open('y_pred.txt', 'w', encoding='utf-8') as f:
    for i in range(y_pred.shape[0]):
        f.write(unicode(y_pred[i])+'\n')

Υποβάλλουμε το αρχείο y_pred.txt στην πλατφόρμα και μας δίνει macro F1-score ίσο με 0.25. Στα πλαίσια της παρούσας εργασίας καλείστε να τροποποιήσετε τον παρακάτω κώδικα ώστε να προβλέψετε τις κατηγορίες αριθμού επιβατών των πτήσεων του test set. Μπορείτε να εφαρμόσετε κάποια μέθοδο επιλογής χαρακτηριστικών στα δεδομένα ώστε να κρατήσετε μόνο ένα υποσύνολο από τα χαρακτηριστικά. Μπορείτε επίσης να δημιουργήσετε νέα χαρακτηριστικά τα οποία ίσως βοηθήσουν στην κατηγοριοποίηση. Μπορείτε επιπλέον να πειραματιστείτε με κάποια μέθοδο μείωσης διάστασης και να διερευνήσετε αν η εφαρμογή της βελτιώνει το αποτέλεσμα της κατηγοριοποίησης. Επίσης, μπορείτε να χρησιμοποιήσετε θορυβώδη ή ανούσια χαρακτηριστικά για να παράγετε νέα χαρακτηριστικά που παρέχουν μεγαλύτερα ποσοστά πληροφορίας. Μπορείτε να χρησιμοποιήσετε διαφορετικούς ταξινομητές ή να συνδυάσετε τα αποτελέσματα περισσότερων από έναν ταξινομητές.

Παράδοση Εργασίας

Η εργασία είναι είτε ατομική ή μπορεί να γίνει σε ομάδες το πολύ 2 ατόμων. Η τελική αξιολόγηση θα βασίζεται τόσο στο macro F1-score που θα επιτύχετε, όσο και στη συνολική προσέγγισή σας στο πρόβλημα. Στα πλαίσια της εργασίας, θα πρέπει να υποβληθούν τα εξής:

  • Μια αναφορά 2 σελίδων, στην οποία θα πρέπει να περιγράψετε την προσέγγιση και τις μεθόδους που χρησιμοποιήσατε. Δεδομένου ότι πρόκειται για ένα πραγματικό πρόβλημα ταξινόμησης, μας ενδιαφέρει να γνωρίζουμε πώς αντιμετωπίσατε κάθε στάδιο του προβλήματος, π.χ. τι είδους αναπαράσταση δεδομένων χρησιμοποιήσατε, τι χαρακτηριστικά χρησιμοποιήσατε, εάν εφαρμόσατε τεχνικές μείωσης διάστασης, ποιούς αλγορίθμους ταξινόμησης δοκιμάσατε και γιατί, την απόδοση των μεθόδων σας (macro F1-score και χρόνο εκπαίδευσης), τυχόν προσεγγίσεις που τελικά δεν λειτούργησαν, αλλά είναι ενδιαφέρον να παρουσιάσετε, και γενικά, ότι νομίζετε ότι είναι ενδιαφέρον να αναφερθεί.
  • Ενα φάκελο με τον κώδικα της εφαρμογής σας.
  • Εναλλακτικά μπορείτε να συνδυάσετε τα δυο παραπάνω σε ένα αρχείο Ipython Notebook.
  • Δημιουργήστε ένα αρχείο .zip που περιέχει τον κώδικα και την αναφορά και υποβάλετέ τον στην πλατφόρμα e-class.
  • **Λήξη προθεσμίας**: 12 Ιανουαρίου 2016.