{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "be0c6fbf", "metadata": {}, "outputs": [], "source": [ "\"\"\"\n", "FastF1 Lap-Level Data Fetcher for HPC F1 AI Strategy System\n", "\n", "Downloads lap-aggregated telemetry and race data from a specific F1 session.\n", "Creates per-lap statistics instead of per-time-sample data.\n", "\n", "Output columns:\n", "- lap_number: The lap number\n", "- total_laps: Total laps in the race\n", "- lap_time: Time taken for this lap\n", "- average_speed: Average speed during the lap (km/h)\n", "- max_speed: Maximum speed during the lap (km/h)\n", "- tire_compound: Tire compound used\n", "- tire_life_laps: Number of laps on current tires\n", "- track_temperature: Average track temperature during the lap\n", "- rainfall: Whether it rained during the lap\n", "\"\"\"\n", "import fastf1\n", "import pandas as pd\n", "import numpy as np" ] }, { "cell_type": "code", "execution_count": 2, "id": "f757cb34", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "req WARNING \tDEFAULT CACHE ENABLED! (318.35 MB) /Users/adipu/Library/Caches/fastf1\n", "core INFO \tLoading data for Italian Grand Prix - Race [v3.6.1]\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 WARNING \tDriver 1 completed the race distance 06:25.888000 before the recorded end of the session.\n", "core WARNING \tDriver 11 completed the race distance 06:19.824000 before the recorded end of the session.\n", "core WARNING \tDriver 55 completed the race distance 06:14.695000 before the recorded end of the session.\n", "core WARNING \tDriver 16 completed the race distance 06:14.511000 before the recorded end of the session.\n", "core WARNING \tDriver 63 completed the race distance 06:07.860000 before the recorded end of the session.\n", "core WARNING \tDriver 44 completed the race distance 05:48.209000 before the recorded end of the session.\n", "core WARNING \tDriver 23 completed the race distance 05:40.782000 before the recorded end of the session.\n", "core WARNING \tDriver 4 completed the race distance 05:40.439000 before the recorded end of the session.\n", "core WARNING \tDriver 14 completed the race distance 05:39.594000 before the recorded end of the session.\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" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Loaded session: 2023 Monza Race\n", "Driver: ALO (Alonso)\n", "Total laps in race: 51.0\n", "Driver laps: 51\n" ] } ], "source": [ "# 1. Load the session\n", "session = fastf1.get_session(2023, 'Monza', 'R')\n", "session.load(telemetry=True, laps=True, weather=True)\n", "\n", "# 2. Pick the driver\n", "driver_laps = session.laps.pick_drivers('ALO')\n", "\n", "# Get total number of laps in the race (maximum lap number from all drivers)\n", "total_laps = session.laps['LapNumber'].max()\n", "\n", "print(f\"Loaded session: 2023 Monza Race\")\n", "print(f\"Driver: ALO (Alonso)\")\n", "print(f\"Total laps in race: {total_laps}\")\n", "print(f\"Driver laps: {len(driver_laps)}\")" ] }, { "cell_type": "code", "execution_count": 3, "id": "aa5e5d8f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Processed lap 10...\n", "Processed lap 20...\n", "Processed lap 30...\n", "Processed lap 40...\n", "Processed lap 50...\n", "\n", "āœ“ Created lap-level dataframe with 51 laps\n", "Laps covered: 1 to 51\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lap_numbertotal_lapslap_timeaverage_speedmax_speedtire_compoundtire_life_lapstrack_temperaturerainfall
01510 days 00:01:33.340000210.17326.0MEDIUM142.5False
12510 days 00:01:28.012000236.87330.0MEDIUM242.5False
23510 days 00:01:27.546000236.40331.0MEDIUM343.2False
34510 days 00:01:27.221000240.13341.0MEDIUM443.2False
45510 days 00:01:27.033000236.09345.0MEDIUM543.1False
56510 days 00:01:27.175000236.74343.0MEDIUM643.3False
67510 days 00:01:26.929000239.72340.0MEDIUM743.6False
78510 days 00:01:26.943000238.45351.0MEDIUM843.6False
89510 days 00:01:27.383000236.81330.0MEDIUM943.6False
910510 days 00:01:27.368000232.42331.0MEDIUM1043.9False
\n", "
" ], "text/plain": [ " lap_number total_laps lap_time average_speed max_speed \\\n", "0 1 51 0 days 00:01:33.340000 210.17 326.0 \n", "1 2 51 0 days 00:01:28.012000 236.87 330.0 \n", "2 3 51 0 days 00:01:27.546000 236.40 331.0 \n", "3 4 51 0 days 00:01:27.221000 240.13 341.0 \n", "4 5 51 0 days 00:01:27.033000 236.09 345.0 \n", "5 6 51 0 days 00:01:27.175000 236.74 343.0 \n", "6 7 51 0 days 00:01:26.929000 239.72 340.0 \n", "7 8 51 0 days 00:01:26.943000 238.45 351.0 \n", "8 9 51 0 days 00:01:27.383000 236.81 330.0 \n", "9 10 51 0 days 00:01:27.368000 232.42 331.0 \n", "\n", " tire_compound tire_life_laps track_temperature rainfall \n", "0 MEDIUM 1 42.5 False \n", "1 MEDIUM 2 42.5 False \n", "2 MEDIUM 3 43.2 False \n", "3 MEDIUM 4 43.2 False \n", "4 MEDIUM 5 43.1 False \n", "5 MEDIUM 6 43.3 False \n", "6 MEDIUM 7 43.6 False \n", "7 MEDIUM 8 43.6 False \n", "8 MEDIUM 9 43.6 False \n", "9 MEDIUM 10 43.9 False " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 3. Get weather data for merging\n", "weather = session.weather_data\n", "weather['SessionTime'] = pd.to_timedelta(weather['Time'])\n", "\n", "# 4. Create lap-level data by aggregating telemetry\n", "lap_data_list = []\n", "\n", "for lap_idx in driver_laps.index:\n", " lap = driver_laps.loc[lap_idx]\n", " lap_number = lap['LapNumber']\n", " \n", " # Skip invalid laps\n", " if pd.isna(lap_number):\n", " continue\n", " \n", " # Get telemetry for this lap\n", " car_data = lap.get_car_data()\n", " \n", " if car_data is not None and len(car_data) > 0:\n", " # Calculate speed statistics\n", " avg_speed = car_data['Speed'].mean()\n", " max_speed = car_data['Speed'].max()\n", " \n", " # Get lap time\n", " lap_time = lap['LapTime']\n", " \n", " # Get tire information\n", " tire_compound = lap['Compound']\n", " tire_life = lap['TyreLife']\n", " \n", " # Get weather data for this lap (use lap start time)\n", " lap_start_time = pd.to_timedelta(lap['LapStartTime'])\n", " \n", " # Find closest weather data\n", " weather_at_lap = weather.iloc[(weather['SessionTime'] - lap_start_time).abs().argmin()]\n", " track_temp = weather_at_lap['TrackTemp']\n", " rainfall = weather_at_lap['Rainfall']\n", " \n", " # Create lap record\n", " lap_record = {\n", " 'lap_number': int(lap_number),\n", " 'total_laps': int(total_laps),\n", " 'lap_time': lap_time,\n", " 'average_speed': round(avg_speed, 2),\n", " 'max_speed': round(max_speed, 2),\n", " 'tire_compound': tire_compound,\n", " 'tire_life_laps': int(tire_life) if pd.notna(tire_life) else None,\n", " 'track_temperature': round(track_temp, 2) if pd.notna(track_temp) else None,\n", " 'rainfall': bool(rainfall)\n", " }\n", " \n", " lap_data_list.append(lap_record)\n", " \n", " # Progress indicator\n", " if lap_number % 10 == 0:\n", " print(f\"Processed lap {int(lap_number)}...\")\n", "\n", "# 5. Create final dataframe\n", "laps_df = pd.DataFrame(lap_data_list)\n", "\n", "print(f\"\\nāœ“ Created lap-level dataframe with {len(laps_df)} laps\")\n", "print(f\"Laps covered: {laps_df['lap_number'].min()} to {laps_df['lap_number'].max()}\")\n", "laps_df.head(10)" ] }, { "cell_type": "code", "execution_count": 4, "id": "b1086b8d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Lap-Level Dataframe Info:\n", "Total laps: 51\n", "\n", "Column types:\n", "lap_number int64\n", "total_laps int64\n", "lap_time timedelta64[ns]\n", "average_speed float64\n", "max_speed float64\n", "tire_compound object\n", "tire_life_laps int64\n", "track_temperature float64\n", "rainfall bool\n", "dtype: object\n", "\n", "Basic statistics:\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
lap_numbertotal_lapslap_timeaverage_speedmax_speedtire_life_lapstrack_temperature
count51.00000051.05151.00000051.00000051.00000051.000000
mean26.00000051.00 days 00:01:27.596803921235.797059333.68627515.41176542.898039
std14.8660690.00 days 00:00:03.0696904347.8550854.9213428.6166730.876924
min1.00000051.00 days 00:01:26.105000191.140000322.0000001.00000040.800000
25%13.50000051.00 days 00:01:26.715000236.105000331.0000008.50000042.500000
50%26.00000051.00 days 00:01:26.943000237.130000332.00000015.00000043.100000
75%38.50000051.00 days 00:01:27.328500238.655000334.00000021.00000043.600000
max51.00000051.00 days 00:01:47.272000241.700000351.00000033.00000044.300000
\n", "
" ], "text/plain": [ " lap_number total_laps lap_time average_speed \\\n", "count 51.000000 51.0 51 51.000000 \n", "mean 26.000000 51.0 0 days 00:01:27.596803921 235.797059 \n", "std 14.866069 0.0 0 days 00:00:03.069690434 7.855085 \n", "min 1.000000 51.0 0 days 00:01:26.105000 191.140000 \n", "25% 13.500000 51.0 0 days 00:01:26.715000 236.105000 \n", "50% 26.000000 51.0 0 days 00:01:26.943000 237.130000 \n", "75% 38.500000 51.0 0 days 00:01:27.328500 238.655000 \n", "max 51.000000 51.0 0 days 00:01:47.272000 241.700000 \n", "\n", " max_speed tire_life_laps track_temperature \n", "count 51.000000 51.000000 51.000000 \n", "mean 333.686275 15.411765 42.898039 \n", "std 4.921342 8.616673 0.876924 \n", "min 322.000000 1.000000 40.800000 \n", "25% 331.000000 8.500000 42.500000 \n", "50% 332.000000 15.000000 43.100000 \n", "75% 334.000000 21.000000 43.600000 \n", "max 351.000000 33.000000 44.300000 " ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Display dataframe info and statistics\n", "print(\"Lap-Level Dataframe Info:\")\n", "print(f\"Total laps: {len(laps_df)}\")\n", "print(f\"\\nColumn types:\")\n", "print(laps_df.dtypes)\n", "print(f\"\\nBasic statistics:\")\n", "laps_df.describe()" ] }, { "cell_type": "code", "execution_count": 5, "id": "b2a3b878", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "āœ“ Saved lap-level data to scripts/ALONSO_2023_MONZA_LAPS.csv\n" ] } ], "source": [ "# Save to CSV\n", "laps_df.to_csv(\"scripts/ALONSO_2023_MONZA_LAPS.csv\", index=False)\n", "print(\"āœ“ Saved lap-level data to scripts/ALONSO_2023_MONZA_LAPS.csv\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "0202372e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "Tire Strategy:\n", " First Lap Last Lap Laps on Compound Avg Speed Max Tire Life\n", "tire_compound \n", "HARD 22 51 30 236.42 33\n", "MEDIUM 1 21 21 234.91 21\n" ] } ], "source": [ "# Show tire strategy\n", "print(\"\\nTire Strategy:\")\n", "tire_stints = laps_df.groupby(['tire_compound']).agg({\n", " 'lap_number': ['min', 'max', 'count'],\n", " 'average_speed': 'mean',\n", " 'tire_life_laps': 'max'\n", "}).round(2)\n", "tire_stints.columns = ['First Lap', 'Last Lap', 'Laps on Compound', 'Avg Speed', 'Max Tire Life']\n", "print(tire_stints)" ] } ], "metadata": { "kernelspec": { "display_name": "base", "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.13.5" } }, "nbformat": 4, "nbformat_minor": 5 }