Problem definition

In order to evaluate PySpark framework, we will apply the same workflow performed by it, but with scikit-learn, using a local processor, without paralel computation.

The problem is a classification, based on flights informations from North America. The dataset used here is the same applied on Spark, and is available in Databricks datasets. It contains 1,391,578 rows, 5 columns and has no null values.

Our workflow will consist of feature engineering, cross-validation, hyperparameter tuning and simple versus ensemble model.

1. Feature Engineering

The main difference between scikit-learn and PySpark Machine Learning library, is that Spark requires one vector containing all features, represented in sparse format. This is not necessary here, we separate the data between X and y, with X being a dataframe with all columns as features.

We still perform the feature engineering, applying the same modifications made to Spark.
We will generate the target variable y, corresponding to delayed flights.
Next we will transform the date column into readable datetime format and bucketize it into intervals of 3 hours along 24 hours.
After we will implement one-hot encoder to the data.
And finally we will also apply scaler to the numerical feature distance.

1.1. Target variable y

The Federal Aviation Administration (FAA) considers a flight to be "delayed" when it arrives 15 minutes or more after its scheduled time. Thus we will be creating the target variable y, accordingly to FAA definition.

We can see that the data is unbalanced, having 3 times more non delayed flights.
However we will work with the data without changing its distribution, in order to evaluate both models performance.

1.2. Column departure

We will first convert the time column into string, so next we can convert it into timestamp.
Then we will apply the bucketizer step for intervals of 3 hours.

1.3. Categorical features

The categorical features origin and destination contain the IATA code for airports of North America. Since there are around 300 different airports in the dataset, we will replace them by their state, reducing to a total of 65 states.

In order to do this, we will need to import a second database, containing the airports informations. We will perform a join between the two tables, to get the corresponding states.

Finally we will apply one-hot encoder to the states.

1.4. Train-test split

Before applying any fitting or prediction, we will split the data into training and test sets. This will ensure that data leakage does not occur during all process.

1.5. Distance scaler

This step was not present in Spark workflow, but here we will also apply a scaler to the numerical feature distance.

2. Models

We will apply the same two classification models applied to Spark: logistic regression and ensemble Random Forest.
Being more simple, Logistic regression will be used as baseline model.
We will perform hyperparameter tuning on them, with grid-search cross-validation and evaluate the best model on the test set.
We will apply two evaluations for both models: ROC-AUC and Confusion Matrix.
The difference here to Spark is that we will declare first the models and their grid search, in order to perform grid-search cross-validation later. Different from Spark, we will not apply pipelines here.

2.1. Evaluators

We don't need to declare both evaluators roc_auc and confusion matrix because they are already implemented as functions by scikit-learn.

2.2. Logistic Regression

The Logistic Regression will be our baseline model, for comparison.
For its hyperparameters we will search for 'C' wich is the inverse of regularization strength λ and 'penalty' which is the norm of Regularization α (L1/L2).

2.3. Ensemble Random Forest

We will declare a Random Forest model and search for its best hyperparameters, through grid-search cross-validation.
For its hyperparameters we will search for 'max_features' wich is the number of features to consider and 'max_depth' which is the maximum depth of the tree.

3. Logistic Regression Cross-Validation

Now through grid-search cross-validation, we may search for the best hyperparameters, on the training set, and use the best model to predict the test set, in order to evaluate the results.

3.1. Hyperparameter Tuning

3.2. Cross-Validation Best Model

3.3. Model Evaluation

4. Ensemble Random Forest Cross-Validation

Now through grid-search cross-validation, we may search for the best hyperparameters, on the training set, and use the best model to predict the test set, in order to evaluate the results.

4.1. Hyperparameter Tuning

4.2. Cross-Validation Best Model

4.3. Model Evaluation

5. Conclusions

Spark is optimized for big data handling. Therefore, it may take more time to deal with small data.
Comparing scikit-learn and Spark performance, we see that Logistic Regression grid-search was faster in scikit-learn, with around 5 min.
Random Forest, however, is impacted by the curse of dimensionality. Here we can see that Spark took around 22 min to perform the grid-search while scikit-learn took around 45 min.
While our data had around 1.4 million rows (30 MB), it is still very small compared to big data, where Spark really shine.

Framework Model Cross-Validation training time
Spark Logistic Regression 8 min
scikit-learn Logistic Regression 5 min
Spark Random Forest 22 min
scikit-learn Random Forest 45 min

Analyzing both models evaluation, we can see that both models performed poorly, heavily impacted by data unbalance. Here Random Forest actually turned out the worst model, because it predicted 0 (not delay) for all cases, still achieving a high accuracy and roc auc score.

Metric Logistic Regression Random Forest
ROC AUC 0.6513 0.6537
Accuracy 0.77 0.77
Precision 0.49 0.00
Recall 0.00 0.00
F1-Score 0.00 0.00

Oversampling or undersampling and other metrics would be proper steps, but we tried to reproduce only similar steps between both frameworks, in order to evaluate both performance.

We conclude here that Spark framework is more recommended for big data. Its parallel processing guarantees less processing time when the data escalates. Also both frameworks may perform differently depending on configurations setup.