New York Taxi data set analysis. Recently I had the opportunity to play... | by Marie Stephen Leo | Towards Data Science

Recently I had the opportunity to play with the New York taxi public data set hosted by Google cloud’s Big Query platform. I decided to apply machine learning techniques on the data set to try and build some predictive models using Python. For this post, I’ll attempt to predict the taxi fare amount. Let’s jump right into it! All the code for this article can be found on Github at Link
First, on inspecting the Google Big Query tables, we notice that there is one table per year. This gives me an idea. I could use the data from 2015 to train my machine learning models and then use the data from 2016 to test the model’s predictive power.
Next, let’s query random 100K rows from 2015 and a random 100K rows from 2016 data using Google’s data lab platform.
Now, let’s begin the process of predicting taxi fare. First, let’s import the necessary packages and load the data into a pandas data frame. I use the %matplotlib inline as I am using a jupyter notebook for the analysis.
From the data frame, we see that each row is one trip while each column is an attribute related to the trip.
I like to start my projects by first building a predictive model purely from intuition. This simple intuitive model will give us our baseline accuracy and we shall try to beat this baseline accuracy using more advanced techniques.
For any predictive model, we need to consider what is the response variable we are trying to predict and what are the feature variables that could have an impact on the said response. In this exercise, the response we want to predict is the fare_amount. Purely from an intuition perspective, we know that taxis generally charge on a fixed initial fee + a per km basis (total distance) + a per minute basis (total duration). Looking back at our data frame columns, we already have a trip_distance column, but we lack a trip_duration column. However, we are provided with pickup and dropoff datetimes, so we can easily calculate the trip_duration using these columns as below.
Now, let us visualize the columns of interest for our simple intuitive model (fare_amount, trip_distance, and trip_duration).
As can be seen from the chart, there are significant outliers for all three columns. Let’s perform an outlier removal and plot again.
Much better! Also, we can clearly see that there is a strong correlation between fare_amount to both the trip_distance and the trip_duration and so we are on the right track.
Before we proceed further, let’s create some helper functions. The first function is to split the data so that the training dataset only has data from 2015 and the test dataset only has data from 2016 as mentioned before. The second function is to calculate some statistics that can be used to evaluate the predictive power of our models. For this exercise, the statistics I choose are Root Mean Square Error (RMSE) which gives the standard deviation of the difference between actual fare_amount and predicted fare_amount in $ and can be calculated as the square root of sklearn’s mean_squared_error(). The R-square gives how much percentage of the actual fare_amount’s variation is predicted by the model and can be directly obtained from sklearn’s r2_score().
Great! Now we are all set to build our first model purely from intuition. Let’s first split the data into the response (y) and features (X), then create the training and testing sets using the above helper function, then fit a simple Linear Regression model on the training dataset and finally, check the model results using the above helper function.
----Training Data results (2015 data set)----RMSE: $5.6R2: 0.79----Test Data results (2016 data set)----RMSE: $5.5R2: 0.81
Not bad for our very first attempt! The testing dataset has an RMSE of $5.5 and we shall use this as our baseline score. Now, let us try to improve this score.
The method I shall employ here is to add more features to the model by the process of feature engineering. Thinking deeper about the problem.
Pickup day of the week and hour of the day could play an important role in demand and traffic conditions leading to an impact on fare
Latitude difference and Longitude difference could be additional data to augment trip_distance’s impact on fare
Pickup and dropoff neighborhoods could have an effect on fare due to additional fees for specific locations?
So, let’s add a few extra features as below. Geohashing is a method to create discrete geographic locations based on absolute latitude and longitudes. You can think of it as creating a common name for locations belonging to the same neighborhood. I use the pygeohash python package which can be installed using pip install pygeohash. Since there is a lot of missing data in the latitude and longitude columns, let’s remove them as well. The new features added are:
Pickup monthPickup day of the weekPickup hour of the dayLattitude differenceLongitude differenceGeohashed pickup locationGeohashed dropoff location
Pickup month
Pickup day of the week
Pickup hour of the day
Lattitude difference
Longitude difference
Geohashed pickup location
Geohashed dropoff location
Looks like there are some outliers in lat_dif and lon_dif, so let’s remove them. Also, since the columns like month, day_of_week, hour_of_day, pickup_geohash, and dropoff_geohash are categorical, let’s encode them using the pandas get_dummies method.
Now let’s split the training and testing datasets and fit a simple Linear Regression model
----Training Data results (2015 data set)----RMSE: $3.5R2: 0.92----Test Data results (2016 data set)----RMSE: $7139352.0R2: -338832003532.88
Yikes! the model has better RMSE on the training dataset but much worse RMSE on the test dataset indicating that the model is overfitting. This necessitates the use of a regularization technique. We can use sklearn’s Lasso Regression for regularization.
----Training Data results (2015 data set)----RMSE: $5.6R2: 0.79----Test Data results (2016 data set)----RMSE: $5.3R2: 0.82
Ok, that’s better from an over-fitting perspective but the Model RMSE did not improve much. Let us now try hyper-parameter tuning to improve the model RMSE. The parameter we can tune for Lasso Regression is called alpha which is a constant that multiplies the L1 penalty term. The default value of alpha is 1. Smaller alpha will make Lasso regression similar to Linear regression by reducing the penalty term.
Since we are using Lasso Regression, there are two methods to perform alpha hyperparameter tuning. The first method is to use sklearn’s generic GridSearchCV which can be used to tune any machine learning model. The second method is to use sklearn’s own LassoCV which is specific to just Lasso regression. Let’s try both and compare their run times as well as the best alpha each can find.
First, let’s run the GridSearchCV method:
GridSearchCV execution time: 3124.58699989Lasso best params: {'alpha': 0.0004012807031942776}----Training Data results (2015 data set)----RMSE: $3.7R2: 0.91----Test Data results (2016 data set)----RMSE: $3.8R2: 0.90
Wow! with an alpha of 0.0004, we were able to obtain a test RMSE of just $3.8! However, the GridSearchCV method took a whopping 3124 seconds to run. That’s almost an hour! Let’s see if LassoCV can run faster but provide us with comparable results. Take note we shall use the same alpha search space for LassoCV to make this a true head to head comparison.
LassoCV execution time: 42.0979998112LassoCV best params: 0.000401280703194----Training Data results (2015 data set)----RMSE: $3.7R2: 0.91----Test Data results (2016 data set)----RMSE: $3.8R2: 0.90
Fantastic! not only does LassoCV give us the same best alpha of 0.0004 to obtain a test RMSE of just $3.8, but it also runs much faster and can complete in just 42 seconds! I must admit, I am surprised by the results myself and will have to dig deeper to understand why LassoCV runs so much faster than GridSearchCV. For now, it looks like the best test score RMSE we can achieve using a linear model is $3.8. This is $1.7 lower than the RMSE of our simple intuitive model! Finally, let’s plot the actual fare vs the predicted fare from the LassoCV model to visually check the correlation
Great! that look’s pretty promising.
We could try to improve the model’s RMSE further by either trying a more complex model like Gradient Boosting or even a Neural Network. We could also add more data into the training set by querying 1 Million rows instead of 100K rows. What do you think? Please leave a comment on how we can improve the model further.
Thank you for reading! Hope you found it interesting. Cheers!