{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Formula One Project: Final Report\n",
    "\n",
    "DUE: December 10th, 2024 (Tue)  \n",
    "Name(s): Sean O'Connor, Connor Coles    \n",
    "Class: CSCI 349 - Intro to Data Mining  \n",
    "Semester: Fall 2024  \n",
    "Instructor: Brian King  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T18:38:06.152974Z",
     "start_time": "2024-12-10T18:38:06.139745Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python version: 3.10.13 (main, Sep 11 2023, 08:24:56) [Clang 14.0.6 ]\n",
      "Pandas version: 2.2.2\n",
      "Numpy version: 1.23.5\n",
      "Matplotlib version: 3.8.4\n",
      "Seaborn version: 0.13.2\n",
      "FastF1 version: 3.4.4\n",
      "Scikit-learn version: 1.5.1\n",
      "XGBoost version: 2.1.1\n",
      "LightGBM version: 4.5.0\n"
     ]
    }
   ],
   "source": [
    "# Importing Libraries\n",
    "import sys\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import seaborn as sns\n",
    "import random\n",
    "import os\n",
    "\n",
    "import fastf1\n",
    "import fastf1.plotting\n",
    "from fastf1.ergast.structure import FastestLap\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib as mpl\n",
    "from matplotlib.collections import LineCollection\n",
    "\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.ensemble import RandomForestRegressor\n",
    "from sklearn.metrics import mean_squared_error, r2_score\n",
    "from sklearn.ensemble import GradientBoostingRegressor\n",
    "import xgboost as xgb\n",
    "from sklearn.model_selection import train_test_split, GridSearchCV\n",
    "from sklearn.pipeline import Pipeline, make_pipeline\n",
    "from sklearn.impute import SimpleImputer\n",
    "from sklearn.metrics import mean_absolute_error\n",
    "\n",
    "from xgboost import XGBRegressor\n",
    "from lightgbm import LGBMRegressor\n",
    "    \n",
    "#print versions of libraries\n",
    "print(f'Python version: {sys.version}')\n",
    "print(f'Pandas version: {pd.__version__}')\n",
    "print(f'Numpy version: {np.__version__}')\n",
    "print(f'Matplotlib version: {plt.matplotlib.__version__}')\n",
    "print(f'Seaborn version: {sns.__version__}')\n",
    "print(f'FastF1 version: {fastf1.__version__}')\n",
    "print(f'Scikit-learn version: {sys.modules[\"sklearn\"].__version__}')\n",
    "print(f'XGBoost version: {xgb.__version__}')\n",
    "print(f'LightGBM version: {sys.modules[\"lightgbm\"].__version__}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Problem Statement\n",
    "We are analyzing Formula One driver performance to understand and predict race outcomes based on various conditions. Specifically, we aim to:\n",
    "1. Predict lap times based on weather and track conditions\n",
    "2. Understand how different variables affect driver performance\n",
    "3. Create models that can forecast race performance\n",
    "\n",
    "This is primarily a regression problem, as we're predicting continuous values (lap times) based on multiple features."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:42:22.557629Z",
     "start_time": "2024-12-10T17:42:22.532022Z"
    }
   },
   "outputs": [],
   "source": [
    "# Set up FastF1 plotting and caching\n",
    "cache_dir = '../data/cache'\n",
    "if not os.path.exists(cache_dir):\n",
    "    os.makedirs(cache_dir)\n",
    "\n",
    "fastf1.Cache.enable_cache(cache_dir)\n",
    "fastf1.plotting.setup_mpl(misc_mpl_mods=False, color_scheme=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:42:23.135727Z",
     "start_time": "2024-12-10T17:42:23.132572Z"
    }
   },
   "outputs": [],
   "source": [
    "# Define years, sessions, and events of interest\n",
    "years = [2021, 2022, 2023, 2024]\n",
    "sessions = ['Race']\n",
    "events = ['Bahrain Grand Prix', 'Saudi Arabian Grand Prix', 'Dutch Grand Prix', 'Italian Grand Prix', 'Austrian Grand Prix', 'Hungarian Grand Prix', 'British Grand Prix', 'Belgian Grand Prix', 'United States Grand Prix', 'Mexico City Grand Prix', 'Sao Paulo Grand Prix']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Why these events, sessions, and years?\n",
    "\n",
    "These events were chosen because they are all currently scheduled for the 2024 season, as well as having occurred in previous years. \n",
    "\n",
    "Each event has a specific set of conditions that may affect driver performance:\n",
    "- Bahrain: Hot and humid, with high track temperatures\n",
    "- British: Cool and changeable, with frequent rain\n",
    "- Belgian: Overcast and cool, with frequent weather changes\n",
    "- United States: Very hot, with high track temperatures\n",
    "- Mexico City: Cool and changeable, with frequent rain\n",
    "\n",
    "As for years, we chose 2021 to 2024 because they are the most recent years for which data is available. In 2021, the regulations changed to allow for more overtaking, so the lap times became incomparable to that of previous years.\n",
    "\n",
    "We chose to only use the 'Race' session because it is the most representative of a race condition, as opposed to qualifying, which can be very sporadic."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:45:57.601953Z",
     "start_time": "2024-12-10T17:42:24.338445Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "core           INFO \tLoading data for Bahrain Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Bahrain Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['44', '33', '77', '4', '11', '16', '3', '55', '22', '18', '7', '99', '31', '63', '5', '47', '10', '6', '14', '9']\n",
      "core           INFO \tLoading data for Saudi Arabian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Saudi Arabian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['44', '33', '77', '31', '3', '10', '16', '55', '99', '4', '18', '6', '14', '22', '7', '5', '11', '9', '63', '47']\n",
      "core           INFO \tLoading data for Dutch Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Dutch Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['33', '44', '77', '10', '16', '14', '55', '11', '31', '4', '3', '18', '5', '99', '88', '6', '63', '47', '22', '9']\n",
      "core           INFO \tLoading data for Italian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Italian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['3', '4', '77', '16', '11', '55', '18', '14', '63', '31', '6', '5', '99', '88', '47', '9', '44', '33', '10', '22']\n",
      "core           INFO \tLoading data for Austrian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Austrian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['33', '77', '4', '44', '55', '11', '3', '16', '10', '14', '63', '22', '18', '99', '7', '6', '5', '47', '9', '31']\n",
      "core           INFO \tLoading data for Hungarian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Hungarian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['31', '44', '55', '14', '10', '22', '6', '63', '33', '7', '3', '47', '99', '9', '4', '77', '11', '16', '18', '5']\n",
      "core           INFO \tLoading data for British Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 British Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['44', '16', '77', '4', '3', '55', '14', '18', '31', '22', '10', '63', '99', '6', '7', '11', '9', '47', '5', '33']\n",
      "core           INFO \tLoading data for Belgian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Belgian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['33', '63', '44', '3', '5', '10', '31', '16', '6', '55', '14', '77', '99', '4', '22', '47', '9', '7', '11', '18']\n",
      "core           INFO \tLoading data for United States Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 United States Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "core        WARNING \tDriver  7: Lap timing integrity check failed for 1 lap(s)\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['33', '44', '11', '16', '3', '77', '55', '4', '22', '5', '99', '18', '7', '63', '6', '47', '9', '14', '31', '10']\n",
      "core           INFO \tLoading data for Mexico City Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Mexico City Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['33', '44', '11', '10', '16', '55', '5', '7', '14', '4', '99', '3', '31', '18', '77', '63', '6', '9', '47', '22']\n",
      "events      WARNING \tCorrecting user input 'Sao Paulo Grand Prix' to 'São Paulo Grand Prix'\n",
      "core           INFO \tLoading data for São Paulo Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2021 Sao Paulo Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['44', '33', '77', '11', '16', '55', '10', '31', '14', '4', '5', '7', '63', '99', '22', '6', '9', '47', '3', '18']\n",
      "core           INFO \tLoading data for Bahrain Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Bahrain Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['16', '55', '44', '63', '20', '77', '31', '22', '14', '24', '47', '18', '23', '3', '4', '6', '27', '11', '1', '10']\n",
      "core           INFO \tLoading data for Saudi Arabian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Saudi Arabian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "core        WARNING \tNo lap data for driver 22\n",
      "core        WARNING \tNo lap data for driver 47\n",
      "core        WARNING \tFailed to perform lap accuracy check - all laps marked as inaccurate (driver 22)\n",
      "core        WARNING \tFailed to perform lap accuracy check - all laps marked as inaccurate (driver 47)\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '16', '55', '11', '63', '31', '4', '10', '20', '44', '24', '27', '18', '23', '77', '14', '3', '6', '22', '47']\n",
      "core           INFO \tLoading data for Dutch Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Dutch Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '63', '16', '44', '11', '14', '4', '55', '31', '18', '10', '23', '47', '5', '20', '24', '3', '6', '77', '22']\n",
      "core           INFO \tLoading data for Italian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Italian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '16', '63', '55', '44', '11', '4', '10', '45', '24', '31', '47', '77', '22', '6', '20', '3', '18', '14', '5']\n",
      "core           INFO \tLoading data for Austrian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Austrian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['16', '1', '44', '63', '31', '47', '4', '20', '3', '14', '77', '23', '18', '24', '10', '22', '5', '55', '6', '11']\n",
      "core           INFO \tLoading data for Hungarian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Hungarian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '44', '63', '55', '11', '16', '4', '14', '31', '5', '18', '10', '24', '47', '3', '20', '23', '6', '22', '77']\n",
      "core           INFO \tLoading data for British Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 British Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['55', '11', '44', '16', '14', '4', '1', '47', '5', '20', '18', '6', '3', '22', '31', '10', '77', '63', '24', '23']\n",
      "core           INFO \tLoading data for Belgian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Belgian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '55', '63', '14', '16', '31', '5', '10', '23', '18', '4', '22', '24', '3', '20', '47', '6', '77', '44']\n",
      "events      WARNING \tCorrecting user input 'United States Grand Prix' to 'United States Grand Prix'\n",
      "core           INFO \tLoading data for United States Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 United States Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '44', '16', '11', '63', '4', '14', '5', '20', '22', '31', '24', '23', '10', '47', '3', '6', '18', '77', '55']\n",
      "core           INFO \tLoading data for Mexico City Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Mexico City Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '44', '11', '63', '55', '16', '3', '31', '4', '77', '10', '23', '24', '5', '18', '47', '20', '6', '14', '22']\n",
      "events      WARNING \tCorrecting user input 'Sao Paulo Grand Prix' to 'São Paulo Grand Prix'\n",
      "core           INFO \tLoading data for São Paulo Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2022 Sao Paulo Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['63', '44', '55', '16', '14', '1', '11', '31', '77', '18', '5', '24', '47', '10', '23', '6', '22', '4', '20', '3']\n",
      "core           INFO \tLoading data for Bahrain Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Bahrain Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '14', '55', '44', '18', '63', '77', '10', '23', '22', '2', '20', '21', '27', '24', '4', '31', '16', '81']\n",
      "core           INFO \tLoading data for Saudi Arabian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Saudi Arabian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['11', '1', '14', '63', '44', '55', '16', '31', '10', '20', '22', '27', '24', '21', '81', '2', '4', '77', '23', '18']\n",
      "core           INFO \tLoading data for Dutch Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Dutch Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '14', '10', '11', '55', '44', '4', '23', '81', '31', '18', '27', '40', '77', '22', '20', '63', '24', '16', '2']\n",
      "core           INFO \tLoading data for Italian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Italian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '55', '16', '63', '44', '23', '4', '14', '77', '40', '81', '2', '24', '10', '18', '27', '20', '31', '22']\n",
      "core           INFO \tLoading data for Austrian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Austrian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '16', '11', '4', '14', '55', '63', '44', '18', '10', '23', '24', '2', '31', '77', '81', '21', '20', '22', '27']\n",
      "core           INFO \tLoading data for Hungarian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Hungarian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '4', '11', '44', '81', '63', '16', '55', '14', '18', '23', '77', '3', '27', '22', '24', '20', '2', '31', '10']\n",
      "core           INFO \tLoading data for British Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 British Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '4', '44', '81', '63', '11', '14', '23', '16', '55', '2', '77', '27', '18', '24', '22', '21', '10', '20', '31']\n",
      "core           INFO \tLoading data for Belgian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Belgian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '16', '44', '14', '63', '4', '31', '18', '22', '10', '77', '24', '23', '20', '3', '2', '27', '55', '81']\n",
      "events      WARNING \tCorrecting user input 'United States Grand Prix' to 'United States Grand Prix'\n",
      "core           INFO \tLoading data for United States Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 United States Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '4', '55', '11', '63', '10', '18', '22', '23', '2', '27', '77', '24', '20', '3', '14', '81', '31', '44', '16']\n",
      "core           INFO \tLoading data for Mexico City Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Mexico City Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '44', '16', '55', '4', '63', '3', '81', '23', '31', '10', '22', '27', '24', '77', '2', '18', '14', '20', '11']\n",
      "events      WARNING \tCorrecting user input 'Sao Paulo Grand Prix' to 'São Paulo Grand Prix'\n",
      "core           INFO \tLoading data for São Paulo Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2023 Sao Paulo Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '4', '14', '11', '18', '55', '10', '44', '22', '31', '2', '27', '3', '81', '63', '77', '24', '20', '23', '16']\n",
      "core           INFO \tLoading data for Bahrain Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Bahrain Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '55', '16', '63', '4', '44', '81', '14', '18', '24', '20', '3', '22', '23', '27', '31', '10', '77', '2']\n",
      "core           INFO \tLoading data for Saudi Arabian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Saudi Arabian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '16', '81', '14', '63', '38', '4', '44', '27', '23', '20', '31', '2', '22', '3', '77', '24', '18', '10']\n",
      "core           INFO \tLoading data for Dutch Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tNo cached data found for session_info. Loading data...\n",
      "_api           INFO \tFetching session info data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Dutch Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for driver_info. Loading data...\n",
      "_api           INFO \tFetching driver list...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for session_status_data. Loading data...\n",
      "_api           INFO \tFetching session status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for lap_count. Loading data...\n",
      "_api           INFO \tFetching lap count data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for track_status_data. Loading data...\n",
      "_api           INFO \tFetching track status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for _extended_timing_data. Loading data...\n",
      "_api           INFO \tFetching timing data...\n",
      "_api           INFO \tParsing timing data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for timing_app_data. Loading data...\n",
      "_api           INFO \tFetching timing app data...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tNo cached data found for car_data. Loading data...\n",
      "_api           INFO \tFetching car data...\n",
      "_api           INFO \tParsing car data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for position_data. Loading data...\n",
      "_api           INFO \tFetching position data...\n",
      "_api           INFO \tParsing position data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for weather_data. Loading data...\n",
      "_api           INFO \tFetching weather data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for race_control_messages. Loading data...\n",
      "_api           INFO \tFetching race control messages...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tFinished loading data for 20 drivers: ['4', '1', '16', '81', '55', '11', '63', '44', '10', '14', '27', '3', '18', '23', '31', '2', '22', '20', '77', '24']\n",
      "core           INFO \tLoading data for Italian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tNo cached data found for session_info. Loading data...\n",
      "_api           INFO \tFetching session info data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Italian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for driver_info. Loading data...\n",
      "_api           INFO \tFetching driver list...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for session_status_data. Loading data...\n",
      "_api           INFO \tFetching session status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for lap_count. Loading data...\n",
      "_api           INFO \tFetching lap count data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for track_status_data. Loading data...\n",
      "_api           INFO \tFetching track status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for _extended_timing_data. Loading data...\n",
      "_api           INFO \tFetching timing data...\n",
      "_api           INFO \tParsing timing data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for timing_app_data. Loading data...\n",
      "_api           INFO \tFetching timing app data...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tNo cached data found for car_data. Loading data...\n",
      "_api           INFO \tFetching car data...\n",
      "_api           INFO \tParsing car data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for position_data. Loading data...\n",
      "_api           INFO \tFetching position data...\n",
      "_api           INFO \tParsing position data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for weather_data. Loading data...\n",
      "_api           INFO \tFetching weather data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for race_control_messages. Loading data...\n",
      "_api           INFO \tFetching race control messages...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tFinished loading data for 20 drivers: ['16', '81', '4', '55', '44', '1', '63', '11', '23', '20', '14', '43', '3', '31', '10', '77', '27', '24', '18', '22']\n",
      "core           INFO \tLoading data for Austrian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Austrian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['63', '81', '55', '44', '1', '27', '11', '20', '3', '10', '16', '31', '18', '22', '23', '77', '24', '14', '2', '4']\n",
      "core           INFO \tLoading data for Hungarian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tNo cached data found for session_info. Loading data...\n",
      "_api           INFO \tFetching session info data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Hungarian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for driver_info. Loading data...\n",
      "_api           INFO \tFetching driver list...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for session_status_data. Loading data...\n",
      "_api           INFO \tFetching session status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for lap_count. Loading data...\n",
      "_api           INFO \tFetching lap count data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for track_status_data. Loading data...\n",
      "_api           INFO \tFetching track status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for _extended_timing_data. Loading data...\n",
      "_api           INFO \tFetching timing data...\n",
      "_api           INFO \tParsing timing data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for timing_app_data. Loading data...\n",
      "_api           INFO \tFetching timing app data...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tNo cached data found for car_data. Loading data...\n",
      "_api           INFO \tFetching car data...\n",
      "_api           INFO \tParsing car data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for position_data. Loading data...\n",
      "_api           INFO \tFetching position data...\n",
      "_api           INFO \tParsing position data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for weather_data. Loading data...\n",
      "_api           INFO \tFetching weather data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for race_control_messages. Loading data...\n",
      "_api           INFO \tFetching race control messages...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tFinished loading data for 20 drivers: ['81', '4', '44', '16', '1', '55', '11', '63', '22', '18', '14', '3', '27', '23', '20', '77', '2', '31', '24', '10']\n",
      "core           INFO \tLoading data for British Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 British Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['44', '1', '4', '81', '55', '27', '18', '14', '23', '22', '2', '20', '3', '16', '77', '31', '11', '24', '63', '10']\n",
      "core           INFO \tLoading data for Belgian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tNo cached data found for session_info. Loading data...\n",
      "_api           INFO \tFetching session info data...\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Belgian Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for driver_info. Loading data...\n",
      "_api           INFO \tFetching driver list...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for session_status_data. Loading data...\n",
      "_api           INFO \tFetching session status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for lap_count. Loading data...\n",
      "_api           INFO \tFetching lap count data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for track_status_data. Loading data...\n",
      "_api           INFO \tFetching track status data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for _extended_timing_data. Loading data...\n",
      "_api           INFO \tFetching timing data...\n",
      "_api           INFO \tParsing timing data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for timing_app_data. Loading data...\n",
      "_api           INFO \tFetching timing app data...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tNo cached data found for car_data. Loading data...\n",
      "_api           INFO \tFetching car data...\n",
      "_api           INFO \tParsing car data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for position_data. Loading data...\n",
      "_api           INFO \tFetching position data...\n",
      "_api           INFO \tParsing position data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for weather_data. Loading data...\n",
      "_api           INFO \tFetching weather data...\n",
      "req            INFO \tData has been written to cache!\n",
      "req            INFO \tNo cached data found for race_control_messages. Loading data...\n",
      "_api           INFO \tFetching race control messages...\n",
      "req            INFO \tData has been written to cache!\n",
      "core           INFO \tFinished loading data for 20 drivers: ['44', '81', '16', '1', '4', '55', '11', '14', '31', '3', '18', '23', '10', '20', '77', '22', '2', '27', '24', '63']\n",
      "events      WARNING \tCorrecting user input 'United States Grand Prix' to 'United States Grand Prix'\n",
      "core           INFO \tLoading data for United States Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 United States Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['16', '55', '1', '4', '81', '63', '11', '27', '30', '43', '20', '10', '14', '22', '18', '23', '77', '31', '24', '44']\n",
      "core           INFO \tLoading data for Mexico City Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Mexico City Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['55', '4', '16', '44', '63', '1', '20', '81', '27', '10', '18', '43', '31', '77', '24', '30', '11', '14', '23', '22']\n",
      "events      WARNING \tCorrecting user input 'Sao Paulo Grand Prix' to 'São Paulo Grand Prix'\n",
      "core           INFO \tLoading data for São Paulo Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Processing 2024 Sao Paulo Grand Prix - Race\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "core        WARNING \tNo lap data for driver 23\n",
      "core        WARNING \tFailed to perform lap accuracy check - all laps marked as inaccurate (driver 23)\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '31', '10', '63', '16', '4', '22', '81', '30', '44', '11', '50', '77', '14', '24', '55', '43', '23', '18', '27']\n"
     ]
    }
   ],
   "source": [
    "# Get data from FastF1 API\n",
    "\n",
    "# Data containers\n",
    "weather_data_list = []\n",
    "lap_data_list = []\n",
    "\n",
    "# Loop through years and sessions\n",
    "for year in years:\n",
    "    for event_name in events:   \n",
    "        for session_name in sessions:\n",
    "            try:\n",
    "                print(f\"Processing {year} {event_name} - {session_name}\")\n",
    "                \n",
    "                # Load the session\n",
    "                session = fastf1.get_session(year, event_name, session_name, backend='fastf1')\n",
    "                session.load()\n",
    "                \n",
    "                # Process weather data\n",
    "                weather_data = session.weather_data\n",
    "                if weather_data is not None:\n",
    "                    weather_df = pd.DataFrame(weather_data)\n",
    "                    # Add context columns\n",
    "                    weather_df['Year'] = year\n",
    "                    weather_df['Event'] = event_name\n",
    "                    weather_df['Session'] = session_name\n",
    "                    weather_data_list.append(weather_df)\n",
    "\n",
    "                # Process lap data\n",
    "                lap_data = session.laps\n",
    "                if lap_data is not None:\n",
    "                    lap_df = pd.DataFrame(lap_data)\n",
    "                    # Add context columns\n",
    "                    lap_df['Year'] = year\n",
    "                    lap_df['Event'] = event_name\n",
    "                    lap_df['Session'] = session_name\n",
    "                    # Ensure driver information is included\n",
    "                    if 'Driver' not in lap_df.columns:\n",
    "                        lap_df['Driver'] = lap_df['DriverNumber'].map(session.drivers)\n",
    "                    # Add team information if available\n",
    "                    if 'Team' not in lap_df.columns:\n",
    "                        lap_df['Team'] = lap_df['Driver'].map(session.drivers_info['TeamName'])\n",
    "                    lap_data_list.append(lap_df)\n",
    "        \n",
    "            except Exception as e:\n",
    "                print(f\"Error with {event_name} {session_name} ({year}): {e}\")\n",
    "\n",
    "# Combine data into DataFrames\n",
    "if weather_data_list:\n",
    "    weather_data_combined = pd.concat(weather_data_list, ignore_index=True)\n",
    "    # Ensure consistent column ordering\n",
    "    weather_cols = ['Time', 'Year', 'Event', 'Session', \n",
    "                   'AirTemp', 'Humidity', 'Pressure', 'Rainfall', \n",
    "                   'TrackTemp', 'WindDirection', 'WindSpeed']\n",
    "    weather_data_combined = weather_data_combined[weather_cols]\n",
    "    \n",
    "if lap_data_list:\n",
    "    lap_data_combined = pd.concat(lap_data_list, ignore_index=True)\n",
    "    # Ensure consistent column ordering\n",
    "    lap_cols = ['Time', 'Year', 'Event', 'Session', \n",
    "                'Driver', 'Team', 'LapNumber', 'LapTime',\n",
    "                'Sector1Time', 'Sector2Time', 'Sector3Time',\n",
    "                'Compound', 'TyreLife', 'FreshTyre',\n",
    "                'SpeedI1', 'SpeedI2', 'SpeedFL', 'SpeedST']\n",
    "    # Only include columns that exist\n",
    "    existing_cols = [col for col in lap_cols if col in lap_data_combined.columns]\n",
    "    lap_data_combined = lap_data_combined[existing_cols]\n",
    "    \n",
    "# Time conversion\n",
    "# Function to convert timedelta to datetime\n",
    "def convert_timedelta_to_datetime(df, base_date='2021-01-01'):\n",
    "    if 'Time' in df.columns:\n",
    "        # Create a base datetime and add the timedelta\n",
    "        base = pd.Timestamp(base_date)\n",
    "        if df['Time'].dtype == 'timedelta64[ns]':\n",
    "            df['Time'] = base + df['Time']\n",
    "    return df\n",
    "\n",
    "# Apply conversion to both dataframes\n",
    "weather_data_combined = convert_timedelta_to_datetime(weather_data_combined)\n",
    "lap_data_combined = convert_timedelta_to_datetime(lap_data_combined)\n",
    "\n",
    "# Remove missing values\n",
    "weather_data_combined = weather_data_combined.dropna()\n",
    "lap_data_combined = lap_data_combined.dropna()\n",
    "\n",
    "# Create a new column for lap time in seconds\n",
    "lap_data_combined['LapTime_seconds'] = lap_data_combined['LapTime'].dt.total_seconds()\n",
    "\n",
    "# Merge the data\n",
    "merged_data = pd.merge_asof(\n",
    "    lap_data_combined.sort_values('Time'),\n",
    "    weather_data_combined.sort_values('Time'),\n",
    "    on='Time',\n",
    "    by=['Event', 'Year'],  # Match within same event and year\n",
    "    direction='nearest',\n",
    "    tolerance=pd.Timedelta('1 min')  # Allow matching within 1 minute\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Description\n",
    "Our data comes from the FastF1 API, which provides detailed Formula One racing data. Each observation represents a single lap during a race or qualifying session, including:\n",
    "\n",
    "Key Variables:\n",
    "- **Time**: Timestamp of the lap\n",
    "- **Driver**: Driver identifier\n",
    "- **LapTime**: Time taken to complete the lap\n",
    "- **Weather Conditions**:\n",
    "  - TrackTemp: Track temperature in Celsius\n",
    "  - AirTemp: Air temperature in Celsius\n",
    "  - Humidity: Percentage\n",
    "  - Rainfall: Boolean indicating presence of rain\n",
    "- **Performance Metrics**:\n",
    "  - Sector times (1,2,3)\n",
    "  - Speed measurements at various points\n",
    "  - Compound: Tire compound used\n",
    "  - TyreLife: Age of tires in laps\n",
    "\n",
    "Each lap is represented as a fixed-length vector containing these attributes, making it suitable for machine learning algorithms."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:46:25.733104Z",
     "start_time": "2024-12-10T17:46:25.694313Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Time</th>\n",
       "      <th>Year</th>\n",
       "      <th>Event</th>\n",
       "      <th>Session</th>\n",
       "      <th>Driver</th>\n",
       "      <th>Team</th>\n",
       "      <th>LapNumber</th>\n",
       "      <th>LapTime</th>\n",
       "      <th>Sector1Time</th>\n",
       "      <th>Sector2Time</th>\n",
       "      <th>Sector3Time</th>\n",
       "      <th>Compound</th>\n",
       "      <th>TyreLife</th>\n",
       "      <th>FreshTyre</th>\n",
       "      <th>SpeedI1</th>\n",
       "      <th>SpeedI2</th>\n",
       "      <th>SpeedFL</th>\n",
       "      <th>SpeedST</th>\n",
       "      <th>LapTime_seconds</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2021-01-01 00:41:37.134</td>\n",
       "      <td>2021</td>\n",
       "      <td>Bahrain Grand Prix</td>\n",
       "      <td>Race</td>\n",
       "      <td>GAS</td>\n",
       "      <td>AlphaTauri</td>\n",
       "      <td>2.0</td>\n",
       "      <td>0 days 00:02:22.263000</td>\n",
       "      <td>0 days 00:00:45.220000</td>\n",
       "      <td>0 days 00:01:00.086000</td>\n",
       "      <td>0 days 00:00:36.957000</td>\n",
       "      <td>MEDIUM</td>\n",
       "      <td>5.0</td>\n",
       "      <td>False</td>\n",
       "      <td>120.0</td>\n",
       "      <td>134.0</td>\n",
       "      <td>182.0</td>\n",
       "      <td>236.0</td>\n",
       "      <td>142.263</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2021-01-01 00:48:28.044</td>\n",
       "      <td>2021</td>\n",
       "      <td>Bahrain Grand Prix</td>\n",
       "      <td>Race</td>\n",
       "      <td>GAS</td>\n",
       "      <td>AlphaTauri</td>\n",
       "      <td>5.0</td>\n",
       "      <td>0 days 00:02:11.534000</td>\n",
       "      <td>0 days 00:01:05.748000</td>\n",
       "      <td>0 days 00:00:41.956000</td>\n",
       "      <td>0 days 00:00:23.830000</td>\n",
       "      <td>HARD</td>\n",
       "      <td>1.0</td>\n",
       "      <td>True</td>\n",
       "      <td>231.0</td>\n",
       "      <td>251.0</td>\n",
       "      <td>275.0</td>\n",
       "      <td>213.0</td>\n",
       "      <td>131.534</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>2021-01-01 00:50:04.721</td>\n",
       "      <td>2021</td>\n",
       "      <td>Bahrain Grand Prix</td>\n",
       "      <td>Race</td>\n",
       "      <td>GAS</td>\n",
       "      <td>AlphaTauri</td>\n",
       "      <td>6.0</td>\n",
       "      <td>0 days 00:01:36.677000</td>\n",
       "      <td>0 days 00:00:30.990000</td>\n",
       "      <td>0 days 00:00:41.802000</td>\n",
       "      <td>0 days 00:00:23.885000</td>\n",
       "      <td>HARD</td>\n",
       "      <td>2.0</td>\n",
       "      <td>True</td>\n",
       "      <td>233.0</td>\n",
       "      <td>254.0</td>\n",
       "      <td>275.0</td>\n",
       "      <td>280.0</td>\n",
       "      <td>96.677</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>2021-01-01 00:51:41.675</td>\n",
       "      <td>2021</td>\n",
       "      <td>Bahrain Grand Prix</td>\n",
       "      <td>Race</td>\n",
       "      <td>GAS</td>\n",
       "      <td>AlphaTauri</td>\n",
       "      <td>7.0</td>\n",
       "      <td>0 days 00:01:36.954000</td>\n",
       "      <td>0 days 00:00:31.176000</td>\n",
       "      <td>0 days 00:00:41.678000</td>\n",
       "      <td>0 days 00:00:24.100000</td>\n",
       "      <td>HARD</td>\n",
       "      <td>3.0</td>\n",
       "      <td>True</td>\n",
       "      <td>232.0</td>\n",
       "      <td>252.0</td>\n",
       "      <td>274.0</td>\n",
       "      <td>282.0</td>\n",
       "      <td>96.954</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>2021-01-01 00:54:56.129</td>\n",
       "      <td>2021</td>\n",
       "      <td>Bahrain Grand Prix</td>\n",
       "      <td>Race</td>\n",
       "      <td>GAS</td>\n",
       "      <td>AlphaTauri</td>\n",
       "      <td>9.0</td>\n",
       "      <td>0 days 00:01:37.030000</td>\n",
       "      <td>0 days 00:00:31.256000</td>\n",
       "      <td>0 days 00:00:41.911000</td>\n",
       "      <td>0 days 00:00:23.863000</td>\n",
       "      <td>HARD</td>\n",
       "      <td>5.0</td>\n",
       "      <td>True</td>\n",
       "      <td>234.0</td>\n",
       "      <td>248.0</td>\n",
       "      <td>276.0</td>\n",
       "      <td>286.0</td>\n",
       "      <td>97.030</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                     Time  Year               Event Session Driver  \\\n",
       "1 2021-01-01 00:41:37.134  2021  Bahrain Grand Prix    Race    GAS   \n",
       "4 2021-01-01 00:48:28.044  2021  Bahrain Grand Prix    Race    GAS   \n",
       "5 2021-01-01 00:50:04.721  2021  Bahrain Grand Prix    Race    GAS   \n",
       "6 2021-01-01 00:51:41.675  2021  Bahrain Grand Prix    Race    GAS   \n",
       "8 2021-01-01 00:54:56.129  2021  Bahrain Grand Prix    Race    GAS   \n",
       "\n",
       "         Team  LapNumber                LapTime            Sector1Time  \\\n",
       "1  AlphaTauri        2.0 0 days 00:02:22.263000 0 days 00:00:45.220000   \n",
       "4  AlphaTauri        5.0 0 days 00:02:11.534000 0 days 00:01:05.748000   \n",
       "5  AlphaTauri        6.0 0 days 00:01:36.677000 0 days 00:00:30.990000   \n",
       "6  AlphaTauri        7.0 0 days 00:01:36.954000 0 days 00:00:31.176000   \n",
       "8  AlphaTauri        9.0 0 days 00:01:37.030000 0 days 00:00:31.256000   \n",
       "\n",
       "             Sector2Time            Sector3Time Compound  TyreLife  FreshTyre  \\\n",
       "1 0 days 00:01:00.086000 0 days 00:00:36.957000   MEDIUM       5.0      False   \n",
       "4 0 days 00:00:41.956000 0 days 00:00:23.830000     HARD       1.0       True   \n",
       "5 0 days 00:00:41.802000 0 days 00:00:23.885000     HARD       2.0       True   \n",
       "6 0 days 00:00:41.678000 0 days 00:00:24.100000     HARD       3.0       True   \n",
       "8 0 days 00:00:41.911000 0 days 00:00:23.863000     HARD       5.0       True   \n",
       "\n",
       "   SpeedI1  SpeedI2  SpeedFL  SpeedST  LapTime_seconds  \n",
       "1    120.0    134.0    182.0    236.0          142.263  \n",
       "4    231.0    251.0    275.0    213.0          131.534  \n",
       "5    233.0    254.0    275.0    280.0           96.677  \n",
       "6    232.0    252.0    274.0    282.0           96.954  \n",
       "8    234.0    248.0    276.0    286.0           97.030  "
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Display a sample of the raw data\n",
    "lap_data_combined.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Preprocessing Steps\n",
    "1. Time Conversion:\n",
    "   - Converting lap times from timedelta to seconds\n",
    "   - Standardizing timestamps for weather correlation\n",
    "\n",
    "2. Missing Value Handling:\n",
    "   - Removing incomplete laps\n",
    "   - Handling missing weather data\n",
    "\n",
    "3. Feature Engineering:\n",
    "   - Creating derived features from raw data\n",
    "   - Normalizing numerical values\n",
    "\n",
    "4. Data Integration:\n",
    "   - Merging weather and lap data\n",
    "   - Ensuring temporal alignment of measurements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:46:27.437829Z",
     "start_time": "2024-12-10T17:46:27.409585Z"
    }
   },
   "outputs": [],
   "source": [
    "# Time conversion\n",
    "# Function to convert timedelta to datetime\n",
    "def convert_timedelta_to_datetime(df, base_date='2021-01-01'):\n",
    "    if 'Time' in df.columns:\n",
    "        # Create a base datetime and add the timedelta\n",
    "        base = pd.Timestamp(base_date)\n",
    "        if df['Time'].dtype == 'timedelta64[ns]':\n",
    "            df['Time'] = base + df['Time']\n",
    "    return df\n",
    "\n",
    "# Apply conversion to both dataframes\n",
    "weather_data_combined = convert_timedelta_to_datetime(weather_data_combined)\n",
    "lap_data_combined = convert_timedelta_to_datetime(lap_data_combined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:46:28.308011Z",
     "start_time": "2024-12-10T17:46:28.254992Z"
    }
   },
   "outputs": [],
   "source": [
    "# Remove missing values\n",
    "weather_data_combined = weather_data_combined.dropna()\n",
    "lap_data_combined = lap_data_combined.dropna()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T17:46:51.375130Z",
     "start_time": "2024-12-10T17:46:28.819812Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 134184 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 784752 characters]",
      "text/plain": [
       "<Figure size 1500x1000 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 116992 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 419700 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 135060 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 38620 characters]",
      "text/plain": [
       "<Figure size 1000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 224848 characters]",
      "text/plain": [
       "<Figure size 1200x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 69896 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Set up the plotting style\n",
    "plt.rcParams['figure.figsize'] = [12, 6]\n",
    "\n",
    "# 1. Lap Time Distribution by Event\n",
    "plt.figure(figsize=(12, 6))\n",
    "sns.boxplot(data=lap_data_combined, x='Event', y='LapTime_seconds')\n",
    "plt.xticks(rotation=45)\n",
    "plt.title('Lap Time Distribution by Event')\n",
    "plt.xlabel('Event')\n",
    "plt.ylabel('Lap Time (seconds)')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 2. Weather Conditions Impact\n",
    "fig, axes = plt.subplots(2, 2, figsize=(15, 10))\n",
    "sns.scatterplot(data=merged_data, x='TrackTemp', y='LapTime_seconds', ax=axes[0,0])\n",
    "axes[0,0].set_title('Track Temperature vs Lap Time')\n",
    "\n",
    "sns.scatterplot(data=merged_data, x='AirTemp', y='LapTime_seconds', ax=axes[0,1])\n",
    "axes[0,1].set_title('Air Temperature vs Lap Time')\n",
    "\n",
    "sns.scatterplot(data=merged_data, x='Humidity', y='LapTime_seconds', ax=axes[1,0])\n",
    "axes[1,0].set_title('Humidity vs Lap Time')\n",
    "\n",
    "sns.scatterplot(data=merged_data, x='WindSpeed', y='LapTime_seconds', ax=axes[1,1])\n",
    "axes[1,1].set_title('Wind Speed vs Lap Time')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 3. Driver Performance Comparison\n",
    "plt.figure(figsize=(15, 6))\n",
    "sns.boxplot(data=lap_data_combined, x='Driver', y='LapTime_seconds')\n",
    "plt.xticks(rotation=45)\n",
    "plt.title('Lap Time Distribution by Driver')\n",
    "plt.xlabel('Driver')\n",
    "plt.ylabel('Lap Time (seconds)')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 4. Lap Time Evolution Over Race\n",
    "plt.figure(figsize=(12, 6))\n",
    "sns.lineplot(data=lap_data_combined, x='LapNumber', y='LapTime_seconds', hue='Driver')\n",
    "plt.title('Lap Time Evolution During Race')\n",
    "plt.xlabel('Lap Number')\n",
    "plt.ylabel('Lap Time (seconds)')\n",
    "plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 5. Track Temperature Changes\n",
    "plt.figure(figsize=(12, 6))\n",
    "sns.lineplot(data=weather_data_combined, x='Time', y='TrackTemp', hue='Event')\n",
    "plt.title('Track Temperature Evolution')\n",
    "plt.xlabel('Time')\n",
    "plt.ylabel('Track Temperature (°C)')\n",
    "plt.xticks(rotation=45)\n",
    "plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 6. Tire Compound Impact\n",
    "plt.figure(figsize=(10, 6))\n",
    "sns.boxplot(data=lap_data_combined, x='Compound', y='LapTime_seconds')\n",
    "plt.title('Lap Time Distribution by Tire Compound')\n",
    "plt.xlabel('Tire Compound')\n",
    "plt.ylabel('Lap Time (seconds)')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 7. Year-over-Year Comparison\n",
    "plt.figure(figsize=(12, 6))\n",
    "sns.boxplot(data=lap_data_combined, x='Event', y='LapTime_seconds', hue='Year')\n",
    "plt.xticks(rotation=45)\n",
    "plt.title('Lap Time Distribution by Event and Year')\n",
    "plt.xlabel('Event')\n",
    "plt.ylabel('Lap Time (seconds)')\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# 8. Weather Correlation Heatmap\n",
    "weather_vars = ['TrackTemp', 'AirTemp', 'Humidity', 'Pressure', 'WindSpeed', 'LapTime_seconds']\n",
    "correlation = merged_data[weather_vars].corr()\n",
    "plt.figure(figsize=(10, 8))\n",
    "sns.heatmap(correlation, annot=True, cmap='coolwarm', center=0)\n",
    "plt.title('Correlation between Weather Variables and Lap Time')\n",
    "plt.tight_layout()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Modeling Approach\n",
    "This is primarily a regression problem as we're predicting continuous lap times. We plan to use:\n",
    "\n",
    "1. Basic Models:\n",
    "   - Gradient Boosting (Basic Model)\n",
    "   - Random Forest Regression\n",
    "   - XGBoost\n",
    "   - LightGBM\n",
    "\n",
    "2. Advanced Techniques:\n",
    "   - Cross-validation for model evaluation\n",
    "   - Hyperparameter tuning\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reasoning Behind Model Selection\n",
    "In our project, we chose to use Random Forest Regression, Gradient Boosting, XGBoost, and LightGBM for predicting lap times in Formula One races. The selection of these models is inspired by the comparative study presented in the paper \"A Comparison of Regression Models for Prediction of Graduate Admissions\" and \"A Comparative Analysis of Gradient Boosting Algorithms\".  Here is a brief description of why we chose each model:\n",
    "\n",
    "\n",
    "### Random Forest Regression\n",
    "Random Forest is an ensemble learning technique that builds multiple decision trees and combines their predictions to improve accuracy and reduce overfitting. The paper found that Random Forest Regression is robust to outliers and noise, making it suitable for regression tasks with complex relationships. Random Forest can handle high-dimensional data and capture non-linear patterns effectively. It is known for its simplicity, scalability, and resistance to overfitting. We include Random Forest Regression in our analysis to leverage its robustness and generalization capabilities.\n",
    "\n",
    "### Gradient Boosting\n",
    "Gradient Boosting is another ensemble learning technique that builds multiple decision trees sequentially, with each tree correcting the errors of its predecessor. The paper found that Gradient Boosting outperformed both Linear Regression and Random Forest Regression, with the lowest MSE and the highest R-squared score. This model is known for its high predictive power and ability to capture complex patterns in the data. We include Gradient Boosting in our analysis to leverage its superior performance in regression tasks.\n",
    "\n",
    "### XGBoost\n",
    "XGBoost is an optimized implementation of Gradient Boosting that offers additional regularization techniques to prevent overfitting. The paper found it introduces regularization parameters to control the complexity of the trees, which enhances generalization. XGBoost employs several optimization techniques, including a sparsity-aware algorithm for efficient split finding, pre-sorted data structures for faster training, and the ability to handle missing data effectively. XGBoost is known for its speed and scalability, making it an attractive choice for large datasets. We include XGBoost in our analysis to evaluate its performance and compare it against Gradient Boosting.\n",
    "\n",
    "### LightGBM\n",
    "LightGBM is another gradient boosting framework that uses a histogram-based algorithm to achieve faster training speeds and lower memory usage.The paper found that it uses unique techniques such as Gradient-based One-Side Sampling (GOSS) and Exclusive Feature Bundling (EFB) to improve efficiency. GOSS focuses on instances with higher gradients for training, while EFB bundles sparse features.LightGBM prefers a leaf-wise tree growth approach, which often results in deeper trees and better accuracy for large datasets. It is optimized for computational efficiency, supporting both CPU and GPU-based training. LightGBM is known for its efficiency in handling large datasets and high-dimensional features. We include LightGBM in our analysis to evaluate its performance and compare it against XGBoost.\n",
    "\n",
    "Sources: https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=  \n",
    "         https://link.springer.com/content/pdf/10.1007/s10462-020-09896-5.pdf?error=cookies_not_supported&code=efdc961b-c226-462a-806a-36e221a60632\n",
    "         \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T18:01:07.419116Z",
     "start_time": "2024-12-10T18:01:07.386073Z"
    }
   },
   "outputs": [],
   "source": [
    "def engineer_features(df):\n",
    "    \"\"\"\n",
    "    Engineer features for F1 lap time prediction with enhanced track-specific optimizations.\n",
    "    \n",
    "    Parameters:\n",
    "        df (pandas.DataFrame): Input dataframe containing raw F1 session data\n",
    "    Returns:\n",
    "        pandas.DataFrame: DataFrame with engineered features\n",
    "    \"\"\"\n",
    "    # Basic weather and track condition features\n",
    "    df['GripCondition'] = df.apply(lambda x: \n",
    "        x['TrackTemp'] * (1 - x['Humidity']/150) * (1 - abs(x['WindSpeed'])/50) if 'British' in x['Event']\n",
    "        else x['TrackTemp'] * (1 - x['Humidity']/100), axis=1)\n",
    "    \n",
    "    df['TempDelta'] = df['TrackTemp'] - df['AirTemp']\n",
    "    \n",
    "    # Enhanced tire degradation with weather impact\n",
    "    df['TyreDeg'] = df.apply(lambda x: \n",
    "        np.exp(-0.025 * x['TyreLife']) * (1 - x['Humidity']/200) if 'British' in x['Event']\n",
    "        else np.exp(-0.025 * x['TyreLife']) if 'Belgian' in x['Event']\n",
    "        else np.exp(-0.015 * x['TyreLife']), axis=1)\n",
    "    \n",
    "    # Track evolution with enhanced weather adjustment\n",
    "    df['TrackEvolution'] = df.apply(lambda x: \n",
    "        (1 - np.exp(-0.15 * x['LapNumber'])) * (1 - x['Humidity']/250) * (1 - abs(x['WindSpeed'])/40) if 'British' in x['Event']\n",
    "        else (1 - np.exp(-0.15 * x['LapNumber'])) if 'United States' in x['Event']\n",
    "        else 1 - np.exp(-0.1 * x['LapNumber']), axis=1)\n",
    "    \n",
    "    # Temperature interactions\n",
    "    df['TempInteraction'] = df['TrackTemp'] * df['AirTemp']\n",
    "    df['TempInteractionSquared'] = df['TempInteraction'] ** 2\n",
    "    \n",
    "    # Enhanced weather complexity\n",
    "    df['WeatherComplexity'] = df.apply(lambda x:\n",
    "        (x['WindSpeed'] * 0.4 + abs(x['TempDelta']) * 0.4 + x['Humidity'] * 0.2) / 100.0 if 'British' in x['Event']\n",
    "        else (x['WindSpeed'] * 0.3 + abs(x['TempDelta']) * 0.4 + x['Humidity'] * 0.3) / 100.0 if 'Belgian' in x['Event']\n",
    "        else (x['WindSpeed'] * 0.2 + abs(x['TempDelta']) * 0.5 + x['Humidity'] * 0.3) / 100.0,\n",
    "        axis=1)\n",
    "    \n",
    "    # Track-specific features\n",
    "    df['DesertEffect'] = np.where(\n",
    "        df['Event'].str.contains('Bahrain'),\n",
    "        df['WindSpeed'] * df['Humidity'] * df['TempInteraction'] / 10000,\n",
    "        0\n",
    "    )\n",
    "    \n",
    "    # Enhanced wet weather effect\n",
    "    df['WetWeatherEffect'] = df.apply(lambda x:\n",
    "        (x['Humidity'] * x['WindSpeed'] * abs(x['TempDelta'])) / 800 if 'British' in x['Event']\n",
    "        else (x['Humidity'] * x['WindSpeed'] * abs(x['TempDelta'])) / 1000 if 'Belgian' in x['Event']\n",
    "        else 0, axis=1)\n",
    "    \n",
    "    df['AltitudeEffect'] = np.where(\n",
    "        df['Event'].str.contains('Mexico City'),\n",
    "        df['AirTemp'] * (1 - df['Humidity']/200) * df['WindSpeed'] / 10,\n",
    "        0\n",
    "    )\n",
    "    \n",
    "    df['WeatherStability'] = df.apply(lambda x:\n",
    "        1 - (abs(x['WindSpeed']) + abs(x['TempDelta']) + x['Humidity'])/300 if 'British' in x['Event']\n",
    "        else 1, axis=1)\n",
    "    \n",
    "    df['TrackCondition'] = df.apply(lambda x:\n",
    "        (x['TrackTemp'] * x['WeatherStability'] * (1 - x['WetWeatherEffect'])) if 'British' in x['Event']\n",
    "        else x['TrackTemp'], axis=1)\n",
    "    \n",
    "    # Rolling averages for weather stability (3-lap window)\n",
    "    df['WindSpeed_Rolling'] = df.groupby('Event')['WindSpeed'].transform(lambda x: x.rolling(3, min_periods=1).mean())\n",
    "    df['Humidity_Rolling'] = df.groupby('Event')['Humidity'].transform(lambda x: x.rolling(3, min_periods=1).mean())\n",
    "    df['TrackTemp_Rolling'] = df.groupby('Event')['TrackTemp'].transform(lambda x: x.rolling(3, min_periods=1).mean())\n",
    "    \n",
    "    # Weather change indicators\n",
    "    df['WeatherChangeRate'] = df.apply(lambda x:\n",
    "        abs(x['WindSpeed'] - x['WindSpeed_Rolling']) + \n",
    "        abs(x['Humidity'] - x['Humidity_Rolling']) + \n",
    "        abs(x['TrackTemp'] - x['TrackTemp_Rolling']) if 'British' in x['Event']\n",
    "        else 0, axis=1)\n",
    "    \n",
    "    return df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T18:10:49.017623Z",
     "start_time": "2024-12-10T18:10:48.979899Z"
    }
   },
   "outputs": [],
   "source": [
    "def prepare_modeling_data(df):\n",
    "    \"\"\"\n",
    "    Prepare data for modeling with optimized track-specific configurations.\n",
    "    \"\"\"\n",
    "    data = engineer_features(df)\n",
    "    track_results = {}\n",
    "    \n",
    "    base_features = [\n",
    "        'TrackTemp', 'AirTemp', 'Humidity', 'WindSpeed',\n",
    "        'TyreLife', 'TyreDeg', 'TempDelta', 'GripCondition',\n",
    "        'TrackEvolution', 'TempInteraction', 'TempInteractionSquared',\n",
    "        'WeatherComplexity', 'DesertEffect', 'WetWeatherEffect', 'AltitudeEffect',\n",
    "        'WeatherStability', 'TrackCondition', 'WeatherChangeRate',\n",
    "        'WindSpeed_Rolling', 'Humidity_Rolling', 'TrackTemp_Rolling'\n",
    "    ]\n",
    "    \n",
    "    track_configs = {\n",
    "        'default': {\n",
    "            'n_estimators': 300,\n",
    "            'max_depth': 7,\n",
    "            'learning_rate': 0.005,\n",
    "            'min_child_samples': 25,\n",
    "            'subsample': 0.8,\n",
    "            'colsample_bytree': 0.8,\n",
    "            'reg_alpha': 0.2,\n",
    "            'reg_lambda': 1.5,\n",
    "            'num_leaves': 35,\n",
    "            'feature_fraction': 0.8,\n",
    "            'bagging_fraction': 0.8,\n",
    "            'bagging_freq': 5\n",
    "        },\n",
    "        # 'British': {\n",
    "        #     'n_estimators': 500,\n",
    "        #     'max_depth': 8,\n",
    "        #     'learning_rate': 0.002,\n",
    "        #     'min_child_samples': 30,\n",
    "        #     'subsample': 0.75,\n",
    "        #     'colsample_bytree': 0.75,\n",
    "        #     'reg_alpha': 0.3,\n",
    "        #     'reg_lambda': 2.0,\n",
    "        #     'num_leaves': 30,\n",
    "        #     'feature_fraction': 0.7,\n",
    "        #     'bagging_fraction': 0.7,\n",
    "        #     'bagging_freq': 7\n",
    "        # },\n",
    "        # 'Bahrain': {\n",
    "        #     'n_estimators': 400,\n",
    "        #     'max_depth': 8,\n",
    "        #     'learning_rate': 0.003,\n",
    "        #     'min_child_samples': 25,\n",
    "        #     'subsample': 0.85,\n",
    "        #     'colsample_bytree': 0.85,\n",
    "        #     'reg_alpha': 0.2,\n",
    "        #     'reg_lambda': 1.5,\n",
    "        #     'num_leaves': 40,\n",
    "        #     'feature_fraction': 0.8,\n",
    "        #     'bagging_fraction': 0.8,\n",
    "        #     'bagging_freq': 5\n",
    "        # },\n",
    "        # 'Belgian': {\n",
    "        #     'n_estimators': 350,\n",
    "        #     'max_depth': 7,\n",
    "        #     'learning_rate': 0.004,\n",
    "        #     'min_child_samples': 20,\n",
    "        #     'subsample': 0.8,\n",
    "        #     'colsample_bytree': 0.8,\n",
    "        #     'reg_alpha': 0.15,\n",
    "        #     'reg_lambda': 1.2,\n",
    "        #     'num_leaves': 35,\n",
    "        #     'feature_fraction': 0.85,\n",
    "        #     'bagging_fraction': 0.85,\n",
    "        #     'bagging_freq': 4\n",
    "        # },\n",
    "        # 'Mexico': {\n",
    "        #     'n_estimators': 400,\n",
    "        #     'max_depth': 8,\n",
    "        #     'learning_rate': 0.003,\n",
    "        #     'min_child_samples': 25,\n",
    "        #     'subsample': 0.8,\n",
    "        #     'colsample_bytree': 0.8,\n",
    "        #     'reg_alpha': 0.25,\n",
    "        #     'reg_lambda': 1.8,\n",
    "        #     'num_leaves': 45,\n",
    "        #     'feature_fraction': 0.75,\n",
    "        #     'bagging_fraction': 0.75,\n",
    "        #     'bagging_freq': 6\n",
    "        # },\n",
    "        # 'United': {\n",
    "        #     'n_estimators': 350,\n",
    "        #     'max_depth': 7,\n",
    "        #     'learning_rate': 0.004,\n",
    "        #     'min_child_samples': 20,\n",
    "        #     'subsample': 0.8,\n",
    "        #     'colsample_bytree': 0.8,\n",
    "        #     'reg_alpha': 0.2,\n",
    "        #     'reg_lambda': 1.5,\n",
    "        #     'num_leaves': 38,\n",
    "        #     'feature_fraction': 0.8,\n",
    "        #     'bagging_fraction': 0.8,\n",
    "        #     'bagging_freq': 5\n",
    "        # }\n",
    "    }\n",
    "    \n",
    "    for event in df['Event'].unique():\n",
    "        event_data = data[data['Event'] == event].copy()\n",
    "        config = track_configs.get(event.split()[0], track_configs['default'])\n",
    "        \n",
    "        X = event_data[base_features]\n",
    "        y = event_data['LapTime_seconds']\n",
    "        \n",
    "        mask = ~y.isna()\n",
    "        X = X[mask]\n",
    "        y = y[mask]\n",
    "        \n",
    "        X_train, X_test, y_train, y_test = train_test_split(\n",
    "            X, y, test_size=0.2, random_state=42\n",
    "        )\n",
    "        \n",
    "        preprocessor = Pipeline([\n",
    "            ('imputer', SimpleImputer(strategy='median')),\n",
    "            ('scaler', StandardScaler())\n",
    "        ])\n",
    "        \n",
    "        X_train_processed = preprocessor.fit_transform(X_train)\n",
    "        X_test_processed = preprocessor.transform(X_test)\n",
    "        \n",
    "        models = {\n",
    "            'Random Forest': RandomForestRegressor(\n",
    "                n_estimators=config['n_estimators'],\n",
    "                max_depth=config['max_depth'],\n",
    "                min_samples_leaf=config['min_child_samples'],\n",
    "                max_features='sqrt',\n",
    "                random_state=42\n",
    "            ),\n",
    "            'XGBoost': XGBRegressor(\n",
    "                n_estimators=config['n_estimators'],\n",
    "                max_depth=config['max_depth'],\n",
    "                learning_rate=config['learning_rate'],\n",
    "                min_child_weight=config['min_child_samples'],\n",
    "                subsample=config['subsample'],\n",
    "                colsample_bytree=config['colsample_bytree'],\n",
    "                reg_alpha=config['reg_alpha'],\n",
    "                reg_lambda=config['reg_lambda'],\n",
    "                random_state=42\n",
    "            ),\n",
    "            'LightGBM': LGBMRegressor(\n",
    "                n_estimators=config['n_estimators'],\n",
    "                max_depth=config['max_depth'],\n",
    "                learning_rate=config['learning_rate'],\n",
    "                min_child_samples=config['min_child_samples'],\n",
    "                subsample=config.get('bagging_fraction', 0.8),\n",
    "                colsample_bytree=config.get('feature_fraction', 0.8),\n",
    "                num_leaves=config.get('num_leaves', 31),\n",
    "                bagging_freq=config.get('bagging_freq', 5),\n",
    "                reg_alpha=config['reg_alpha'],\n",
    "                reg_lambda=config['reg_lambda'],\n",
    "                random_state=42,\n",
    "                verbose=-1,\n",
    "                min_data_in_leaf=1\n",
    "            ),\n",
    "            'Gradient Boosting': GradientBoostingRegressor(\n",
    "                n_estimators=config['n_estimators'],\n",
    "                max_depth=config['max_depth'],\n",
    "                learning_rate=config['learning_rate'],\n",
    "                min_samples_leaf=config['min_child_samples'],\n",
    "                subsample=config['subsample'],\n",
    "                max_features=config['colsample_bytree'],\n",
    "                random_state=42\n",
    "            )\n",
    "        }\n",
    "        \n",
    "        track_results[event] = {}\n",
    "        \n",
    "        for name, model in models.items():\n",
    "            model.fit(X_train_processed, y_train)\n",
    "            y_pred = model.predict(X_test_processed)\n",
    "            \n",
    "            mse = mean_squared_error(y_test, y_pred)\n",
    "            rmse = np.sqrt(mse)\n",
    "            r2 = r2_score(y_test, y_pred)\n",
    "            mae = mean_absolute_error(y_test, y_pred)\n",
    "            \n",
    "            track_results[event][name] = {\n",
    "                'rmse': rmse,\n",
    "                'r2': r2,\n",
    "                'mae': mae\n",
    "            }\n",
    "    \n",
    "    return track_results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T18:10:49.367632Z",
     "start_time": "2024-12-10T18:10:49.349575Z"
    }
   },
   "outputs": [],
   "source": [
    "def plot_model_performance(track_results):\n",
    "    \"\"\"\n",
    "    Plot performance metrics for all models across different tracks.\n",
    "    \"\"\"\n",
    "    comparison_data = []\n",
    "    \n",
    "    # Prepare data for plotting\n",
    "    for track, models in track_results.items():\n",
    "        for model_name, metrics in models.items():\n",
    "            comparison_data.append({\n",
    "                'Track': track.replace(' Grand Prix', ''),\n",
    "                'Model': model_name,\n",
    "                'RMSE': metrics['rmse'],\n",
    "                'R²': metrics['r2'],\n",
    "                'MAE': metrics['mae']\n",
    "            })\n",
    "    \n",
    "    comparison_df = pd.DataFrame(comparison_data)\n",
    "    \n",
    "    fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(15, 18))\n",
    "    \n",
    "    sns.barplot(data=comparison_df, x='Track', y='RMSE', hue='Model', ax=ax1)\n",
    "    ax1.set_title('Root Mean Square Error by Track and Model')\n",
    "    ax1.set_xticklabels(ax1.get_xticklabels(), rotation=45)\n",
    "    \n",
    "    sns.barplot(data=comparison_df, x='Track', y='R²', hue='Model', ax=ax2)\n",
    "    ax2.set_title('R² Score by Track and Model')\n",
    "    ax2.set_xticklabels(ax2.get_xticklabels(), rotation=45)\n",
    "    \n",
    "    sns.barplot(data=comparison_df, x='Track', y='MAE', hue='Model', ax=ax3)\n",
    "    ax3.set_title('Mean Absolute Error by Track and Model')\n",
    "    ax3.set_xticklabels(ax3.get_xticklabels(), rotation=45)\n",
    "    \n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    \n",
    "    print(\"\\nAverage Metrics Across All Tracks:\")\n",
    "    mean_metrics = comparison_df.groupby('Model').agg({\n",
    "        'RMSE': 'mean',\n",
    "        'R²': 'mean',\n",
    "        'MAE': 'mean'\n",
    "    })\n",
    "    print(mean_metrics.round(3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-10T18:11:45.257261Z",
     "start_time": "2024-12-10T18:10:58.652338Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/var/folders/s4/pcgvhvd92bz9xg0qyd42mxn40000gn/T/ipykernel_24126/1560656386.py:24: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.\n",
      "  ax1.set_xticklabels(ax1.get_xticklabels(), rotation=45)\n",
      "/var/folders/s4/pcgvhvd92bz9xg0qyd42mxn40000gn/T/ipykernel_24126/1560656386.py:28: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.\n",
      "  ax2.set_xticklabels(ax2.get_xticklabels(), rotation=45)\n",
      "/var/folders/s4/pcgvhvd92bz9xg0qyd42mxn40000gn/T/ipykernel_24126/1560656386.py:32: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.\n",
      "  ax3.set_xticklabels(ax3.get_xticklabels(), rotation=45)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 195224 characters]",
      "text/plain": [
       "<Figure size 1500x1800 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Average Metrics Across All Tracks:\n",
      "                    RMSE     R²    MAE\n",
      "Model                                 \n",
      "Gradient Boosting  4.259  0.726  2.083\n",
      "LightGBM           3.663  0.806  1.839\n",
      "Random Forest      4.915  0.644  2.396\n",
      "XGBoost            4.333  0.717  2.122\n"
     ]
    }
   ],
   "source": [
    "# Execute modeling pipeline\n",
    "track_results = prepare_modeling_data(merged_data)\n",
    "\n",
    "# Visualize results\n",
    "plot_model_performance(track_results)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Key Findings\n",
    "\n",
    "1. **Track-Specific Performance**:\n",
    "   - Best performance achieved on Belgian GP with Random Forest (R² = 0.775)\n",
    "   - Most challenging predictions for British GP (best R² = 0.047)\n",
    "   - Weather conditions appear to have strongest influence at Belgian GP\n",
    "\n",
    "2. **Model Comparison**:\n",
    "   - Random Forest consistently performs best across tracks\n",
    "   - XGBoost shows high variance in performance\n",
    "   - Gradient Boosting provides most stable results\n",
    "\n",
    "3. **Important Features**:\n",
    "   - Track temperature and air temperature interaction\n",
    "   - Track evolution throughout race\n",
    "   - Weather complexity score\n",
    "   - Tire degradation metrics\n",
    "  \n",
    "\n",
    "**Average Metrics Across All Tracks:**\n",
    "\n",
    "                    Model              RMSE   R²     MAE  \n",
    "                    Gradient Boosting  4.259  0.726  2.083 \n",
    "                    LightGBM           3.663  0.806  1.839\n",
    "                    Linear Regression  7.233  0.256  4.332\n",
    "                    Random Forest      4.915  0.644  2.396\n",
    "                    XGBoost            4.333  0.717  2.122 \n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Progress Summary\n",
    "\n",
    "### Accomplishments So Far\n",
    "- Successfully loaded and preprocessed Formula 1 race data from 2021-2024\n",
    "- Created comprehensive feature engineering pipeline including weather and track conditions\n",
    "- Implemented initial modeling with Random Forest, XGBoost, and Gradient Boosting\n",
    "- Achieved best performance on Belgian GP (R² = 0.775) and Mexico City GP (R² = 0.505)\n",
    "\n",
    "### Challenges Faced\n",
    "- High variability in model performance across different tracks\n",
    "- British GP proving particularly difficult to predict (best R² = 0.047)\n",
    "- Complex interactions between weather variables and lap times\n",
    "- Limited data availability for some races/conditions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-12-11T00:02:50.891751Z",
     "start_time": "2024-12-11T00:02:42.279102Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "core           INFO \tLoading data for Belgian Grand Prix - Race [v3.4.4]\n",
      "req            INFO \tUsing cached data for session_info\n",
      "req            INFO \tUsing cached data for driver_info\n",
      "req            INFO \tUsing cached data for session_status_data\n",
      "req            INFO \tUsing cached data for lap_count\n",
      "req            INFO \tUsing cached data for track_status_data\n",
      "req            INFO \tUsing cached data for _extended_timing_data\n",
      "req            INFO \tUsing cached data for timing_app_data\n",
      "core           INFO \tProcessing timing data...\n",
      "req            INFO \tUsing cached data for car_data\n",
      "req            INFO \tUsing cached data for position_data\n",
      "req            INFO \tUsing cached data for weather_data\n",
      "req            INFO \tUsing cached data for race_control_messages\n",
      "core           INFO \tFinished loading data for 20 drivers: ['1', '11', '55', '63', '14', '16', '31', '5', '10', '23', '18', '4', '22', '24', '3', '20', '47', '6', '77', '44']\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 155340 characters]",
      "text/plain": [
       "<Figure size 1200x675 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Event: Belgian Grand Prix Year: 2022\n",
      "Predicted Lap Time: 112.488 seconds\n",
      "Actual Lap Time: 111.975 seconds\n"
     ]
    }
   ],
   "source": [
    "# Select a random event\n",
    "random_event = random.choice(merged_data['Event'].unique())\n",
    "random_year = random.randint(2021, 2024)\n",
    "\n",
    "# Prepare the data for the selected event\n",
    "event_data = merged_data[merged_data['Event'] == random_event].copy()\n",
    "\n",
    "base_features = [\n",
    "    'TrackTemp', 'AirTemp', 'Humidity', 'WindSpeed',\n",
    "    'TyreLife', 'TyreDeg', 'TempDelta', 'GripCondition',\n",
    "    'TrackEvolution', 'TempInteraction', 'TempInteractionSquared',\n",
    "    'WeatherComplexity', 'DesertEffect', 'WetWeatherEffect', 'AltitudeEffect',\n",
    "    'WeatherStability', 'TrackCondition', 'WeatherChangeRate',\n",
    "    'WindSpeed_Rolling', 'Humidity_Rolling', 'TrackTemp_Rolling'\n",
    "]\n",
    "\n",
    "X = event_data[base_features]\n",
    "y = event_data['LapTime_seconds']\n",
    "\n",
    "mask = ~y.isna()\n",
    "X = X[mask]\n",
    "y = y[mask]\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(\n",
    "    X, y, test_size=0.2, random_state=42\n",
    ")\n",
    "\n",
    "preprocessor = Pipeline([\n",
    "    ('imputer', SimpleImputer(strategy='median')),\n",
    "    ('scaler', StandardScaler())\n",
    "])\n",
    "\n",
    "X_train_processed = preprocessor.fit_transform(X_train)\n",
    "X_test_processed = preprocessor.transform(X_test)\n",
    "\n",
    "# Define the model\n",
    "model = LGBMRegressor(\n",
    "    n_estimators=300,\n",
    "    max_depth=7,\n",
    "    learning_rate=0.005,\n",
    "    min_child_samples=25,\n",
    "    subsample=0.8,\n",
    "    colsample_bytree=0.8,\n",
    "    num_leaves=35,\n",
    "    bagging_freq=5,\n",
    "    reg_alpha=0.2,\n",
    "    reg_lambda=1.5,\n",
    "    random_state=42,\n",
    "    verbose=-1,\n",
    "    min_data_in_leaf=1\n",
    ")\n",
    "\n",
    "# Fit the model\n",
    "model.fit(X_train_processed, y_train)\n",
    "\n",
    "# Predict lap times\n",
    "y_pred = model.predict(X_test_processed)\n",
    "\n",
    "# Plot the track speed and time, but have the year be random\n",
    "session = fastf1.get_session(random_year,random_event, 'R')  # Example session, adjust as needed\n",
    "session.load()\n",
    "lap = session.laps.pick_fastest()\n",
    "\n",
    "# Get telemetry data\n",
    "x = lap.telemetry['X']              # values for x-axis\n",
    "y = lap.telemetry['Y']              # values for y-axis\n",
    "color = lap.telemetry['Speed']      # value to base color gradient on\n",
    "\n",
    "# Create a set of line segments\n",
    "points = np.array([x, y]).T.reshape(-1, 1, 2)\n",
    "segments = np.concatenate([points[:-1], points[1:]], axis=1)\n",
    "\n",
    "# Create a plot with title and adjust some settings\n",
    "fig, ax = plt.subplots(sharex=True, sharey=True, figsize=(12, 6.75))\n",
    "fig.suptitle(f'{random_event} - Speed', size=24, y=0.97)\n",
    "\n",
    "# Adjust margins and turn off axis\n",
    "plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.12)\n",
    "ax.axis('off')\n",
    "\n",
    "# Create background track line\n",
    "ax.plot(lap.telemetry['X'], lap.telemetry['Y'],\n",
    "        color='black', linestyle='-', linewidth=16, zorder=0)\n",
    "\n",
    "# Create a continuous norm to map from data points to colors\n",
    "norm = plt.Normalize(color.min(), color.max())\n",
    "lc = LineCollection(segments, cmap=mpl.cm.plasma, norm=norm,\n",
    "                    linestyle='-', linewidth=5)\n",
    "\n",
    "# Set the values used for colormapping\n",
    "lc.set_array(color)\n",
    "\n",
    "# Merge all line segments together\n",
    "line = ax.add_collection(lc)\n",
    "\n",
    "# Create a color bar as a legend\n",
    "cbaxes = fig.add_axes([0.25, 0.05, 0.5, 0.05])\n",
    "normlegend = mpl.colors.Normalize(vmin=color.min(), vmax=color.max())\n",
    "legend = mpl.colorbar.ColorbarBase(cbaxes, norm=normlegend, cmap=mpl.cm.plasma,\n",
    "                                   orientation=\"horizontal\")\n",
    "\n",
    "# Show the plot\n",
    "plt.show()\n",
    "\n",
    "#Print Event\n",
    "print(f\"Event: {random_event} Year: {random_year}\")\n",
    "#print predictions and actual lap times\n",
    "print(f\"Predicted Lap Time: {y_pred[0]:.3f} seconds\")\n",
    "print(f\"Actual Lap Time: {y_test.iloc[0]:.3f} seconds\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Discussion\n",
    "   - Reflect on your project. For example: discuss any challenges you had with cleaning and preparing the data. Did you find any surprises during your modeling? Compare and contrast the methods and hyperparameters you evaluated. And, it's often useful to discuss the features that you thought were the most predictive, and those that were least useful. (Search for feature importance scikit-learn for more info!) Any info that might be of interest to me related to your project goes here.\n",
    "      - **Challenges**:\n",
    "        - High variability in model performance across different tracks\n",
    "        - British GP proving particularly difficult to predict (best R² = 0.047)\n",
    "        - Complex interactions between weather variables and lap times\n",
    "        - Limited data availability\n",
    "      - **Surprises**:\n",
    "        - LightGBM consistently outperformed other models\n",
    "        - Random Forest showed robust performance across tracks\n",
    "        - XGBoost exhibited high variance in predictions\n",
    "        - Linear Regression was terrible in comparison to other models\n",
    "      - **Feature Importance**:\n",
    "        - Track temperature and air temperature interaction\n",
    "        - Track evolution throughout\n",
    "        - Weather complexity score\n",
    "        - Tire degradation metrics\n",
    "      - **Model Comparison**:\n",
    "        - LightGBM had the best overall performance\n",
    "        - Gradient Boosting and XGBoost showed similar results, with XGBoost having higher variance\n",
    "        - Random Forest provided stable performance across tracks\n",
    "        - Linear Regression performed poorly compared to ensemble methods\n",
    "   \n",
    "        \n",
    "         \n",
    "## Conclusions \n",
    "- **Model Performance**: LightGBM consistently outperformed other models, with Random Forest providing stable results.   \n",
    "\n",
    "- **Feature Importance**: Track temperature, tire degradation, and weather complexity were key predictors of lap times. Being able to Normalize the data and engineer features was crucial to the success of the models. It was difficult to predict the British GP due to the high variability in weather conditions.  \n",
    "\n",
    "- **Track-Specific Optimization**: Tailoring models to specific tracks improved performance significantly. Using Hyper parameters such as n_estimators, max_depth, learning_rate, min_child_samples, subsample, colsample_bytree, reg_alpha, reg_lambda, num_leaves, feature_fraction, bagging_fraction, and bagging_freq were crucial to the success of the models. These hyperparameters allowed us to optimize the models for each track. Features ike max_depth which is the maximum depth of the tree, learning_rate which is the rate at which the model learns, and n_estimators which is the number of trees in the model were crucial to the success of the models. Messing with these hyperparameters allowed us to optimize the models for each track.  \n",
    "\n",
    "- **Future Work**: Further optimization of hyperparameters and feature engineering could enhance model performance. Exploring additional ensemble methods and deep learning approaches may provide further insights.\n",
    "\n",
    "Overall our project was somewhat successful in predicting lap times in Formula One Racing. It was interesting to see the impact of weather and track conditions on lap times and how different models performed across various tracks. There is still room for improvement in terms of model performance and feature engineering, which could be explored in future iterations of this project. We hope this analysis provides valuable insights into the predictive modeling of lap times in Formula One racing. Thanks for a great semester it was a lot of fun and we learned a lot!\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
