This project predicts the duration of taxi trips in New York City using supervised machine learning, with a strong emphasis on feature engineering, model comparison, and real-world deployment. It is divided into two major phases: the first focuses on EDA and interpretable feature creation using Ridge Regression, and the second benchmarks more advanced models—including XGBoost, Neural Networks, and a stacked ensemble—followed by hyperparameter tuning and API Integration.
This project is structured into two main parts:
- Extensive exploratory data analysis (EDA) was conducted to identify patterns in spatial, temporal, and behavioral variables.
- More than 30 engineered features were crafted, ranging from distance metrics and spatial interactions to temporal and behavioral indicators.
- A Ridge Regression model (α = 1) was used to isolate the effect of engineered features while minimizing the complexity of the model.
- Rigorous IQR-based outlier removal was tuned (k = 8) to balance between data cleaning and generalization.
- Log transformation was applied to the target variable (
trip_duration) to reduce skewness and stabilize model training.
-
Benchmarked multiple models including:
- Ridge Regression
- XGBoost
- Neural Network
- A stacked ensemble using Ridge & XGBoost as base learners and a Neural Network as the meta-learner
-
Conducted RandomizedSearchCV for hyperparameter tuning (e.g.,
max_depth=13,n_estimators=137for XGBoost). -
XGBoost outperformed all other models and was selected for production due to its strong generalization and interpretability.
-
A lightweight API was developed to serve real-time predictions using the best-performing model.
-
A comprehensive command-line interface (CLI) is provided for flexible training, tuning, and deployment of all models in the project.
The dataset includes detailed records of NYC taxi trips with attributes such as timestamps, coordinates, and passenger count.
-
Target:
trip_duration(in seconds) -
Features include:
pickup_latitude,pickup_longitudedropoff_latitude,dropoff_longitudepassenger_count,vendor_id, and more
| Dataset | R² Score | RMSE |
|---|---|---|
| Training Set | 0.68638 | 0.43218 |
| Validation Set | 0.68688 | 0.43290 |
| Model | Val R² | Val RMSE | Comments |
|---|---|---|---|
| XGBoost | 0.759 | 0.381 | Selected for production |
| Stacked Ensemble | 0.754 | 0.385 | Good but more complex |
| Neural Network | 0.747 | 0.390 | Competitive, less interpretable |
| Ridge Regression | 0.689 | 0.433 | Strong linear baseline |
| Dataset | R² Score | RMSE |
|---|---|---|
| Test Set | 0.759 | 0.380 |
This report presents a complete machine learning pipeline for NYC taxi trip duration prediction. It includes:
- Extensive Feature Engineering: From spatial transformations (e.g., Haversine distance, lat/lon sums) to temporal patterns and interaction effects.
- Robust Data Preprocessing: Outlier detection using the IQR method (with an optimal multiplier of k = 8), log transformation of the target variable, and strict separation of training and validation sets to prevent data leakage.
- Model Development and Comparison: Evaluation of Ridge Regression, XGBoost, Neural Network, and a stacked ensemble—with XGBoost emerging as the top-performing model.
- Hyperparameter Tuning: Randomized search was used to identify the best configurations for each model, improving generalization and stability.
- Final Results: The best model (XGBoost) achieved an R² score of 0.759 and RMSE of 0.380 on the test set, demonstrating strong predictive performance.
For a detailed breakdown of the methodology, engineered features, data insights, model development, and performance metrics, refer to the full project report:
NYC-Taxi-Trip-Duration-Prediction/
├── notebooks/ # Exploratory data analysis and feature engineering notebooks
│ └── trip_duration.ipynb
│
├── summary/ # Project summary
│ └── project_report.pdf
│
├── scripts/ # Python scripts for training, testing, and preprocessing
│ ├── trip_duration_train.py # Model training pipeline
│ ├── trip_duration_test.py # Model evaluation script
│
│ ├── trip_duration_utils_data.py # Data loading and cleaning utilities
│ ├── trip_duration_utils_preprocess.py # Feature engineering and transformation
│ ├── trip_duration_utils_eval.py # Model evaluation metrics and helpers
│ └── cli_args.py # Command-line argument definitions
│
├── api/ # REST API for serving model predictions
│ └── predict_api.py
│
├── saved_models/ # Serialized models
│ └── final_xgb.pkl
│
├── requirements.txt # Python dependencies for reproducibility
└── README.md # Project overview, instructions, and usage guide
Clone the repository:
git clone https://github.com/your-username/NYC-Taxi-Trip-Duration-Prediction.git
cd NYC-Taxi-Trip-Duration-PredictionInstall dependencies:
pip install -r requirements.txtPython 3.9 or later is required for full compatibility. All models and preprocessing steps are version-locked for reproducibility.
This project includes a fully configurable command-line interface using argparse, enabling flexible training, tuning, and deployment.
| Argument | Description |
|---|---|
--train_dir |
Path to the training dataset CSV file |
--test_dir |
Path to the testing dataset CSV file |
--save-dir |
Directory to save the trained model |
--load-dir |
Path to load a saved model for inference |
--model-name |
Name of the saved model file (e.g., ridge_model.pkl) |
| Argument | Description |
|---|---|
--model |
Select the model: RR (Ridge), XGB (XGBoost), or NN (Neural Network) |
--use-stacking |
Enable stacked ensemble using Ridge, XGBoost, and Neural Network |
--random-search |
Use RandomizedSearchCV for hyperparameter tuning |
| Argument | Description |
|---|---|
--categorical-features |
List of categorical features to one-hot encode |
--scaling |
Scaling method: standard, robust, or minmax |
--iqr-multiplier |
IQR threshold multiplier for outlier removal (default: 8) |
| Argument | Description |
|---|---|
--ridge-alpha |
Regularization strength (α) |
--ridge-max-iter |
Maximum iterations (default: None) |
| Argument | Description |
|---|---|
--xgb-n-estimators |
Number of boosting rounds |
--xgb-max-depth |
Maximum tree depth |
--xgb-learning-rate |
Learning rate (eta) |
| Argument | Description |
|---|---|
--nn-hidden-layers |
Comma-separated hidden layer sizes (e.g., 64,32) |
--nn-max-iter |
Maximum training iterations |
--nn-activation |
Activation function: relu, tanh, or logistic |
--nn-lr |
Learning rate |
Train a Ridge Regression model with default preprocessing:
python scripts/train/trip_duration_train.py --model RRTrain a tuned XGBoost model using RobustScaler and stacking:
python scripts/train/trip_duration_train.py --model XGB --use-stacking --scaling robust --random-search- Python, pandas, NumPy, datetime
- scikit-learn (preprocessing, Ridge, RandomizedSearchCV)
- XGBoost
- PyTorch (Neural Network + Ensemble)
- matplotlib, seaborn (EDA)
- haversine (geospatial distance)
- FastAPI (API deployment)
A RESTful API is provided to serve model predictions using the final XGBoost model.
python api/predict_api.pyThe endpoint expects a JSON payload with the following fields:
{
"pickup_datetime": "2025-01-15T08:45:00",
"vendor_id": 2,
"passenger_count": 1,
"pickup_longitude": -73.985428,
"pickup_latitude": 40.748817,
"dropoff_longitude": -73.985130,
"dropoff_latitude": 40.758896
}pickup_datetime(ISO 8601): e.g.,"2025-01-15T08:45:00"vendor_id: 1 or 2passenger_count: between 1 and 6pickup_latitude,pickup_longitude,dropoff_latitude,dropoff_longitude: float values for location
curl -X POST http://127.0.0.1:8000/predict/ \
-H "Content-Type: application/json" \
-d '{
"pickup_datetime": "2025-01-15T08:45:00",
"vendor_id": 2,
"passenger_count": 1,
"pickup_longitude": -73.985428,
"pickup_latitude": 40.748817,
"dropoff_longitude": -73.985130,
"dropoff_latitude": 40.758896
}'{
"prediction": 9.37
}prediction: Estimated trip duration in minutes, rounded to two decimal places- Internally, the model returns a log-transformed prediction which is exponentiated and converted to minutes before being returned.
If the input is invalid (e.g., missing fields or out-of-range values), the API responds with:
{
"detail": "Error message explaining what went wrong"
}Author: Taher Alabbar
Email: t.alabbar.ca@gmail.com, LinkedIn