F1 Data Analysis - Time Penalties in a Season
In today's post, let's look at an example of how to use the FastF1 Python library to find all the time penalties from the 2023 F1 season. You could Google this, but it's more fun to do it ourselves, right? Plus, this way, we can easily look up penalties from other seasons too.
If you're not already familiar with the FastF1 or Python in general, check out my introductory post below, which will get you up to speed in no time.
Get All Race Control Messages from a Specific Race
To begin, the following Python code demonstrates how to use the fastf1
Python library to retrieve race control messages from a specific Formula 1 race, in this case, the 2023 Abu Dhabi Grand Prix.
import fastf1
import pandas as pd
pd.set_option('display.max_rows', None)
fastf1.Cache.enable_cache('cache_dir')
session = fastf1.get_session(2023,'Abu Dhabi','R')
session.load()
messages = session.race_control_messages.loc[:,['Time', 'Message']]
print(messages)
- Importing Libraries: The code begins by importing the necessary libraries,
fastf1
for accessing F1 data andpandas
(aliased aspd
) for data manipulation and analysis. - Setting Display Option:
pd.set_option('display.max_rows', None)
configures pandas to display all rows of the DataFrame without truncation. This is useful for viewing all race control messages without missing any due to output limits. - Enabling Cache:
fastf1.Cache.enable_cache('cache_dir')
sets up a cache directory. This improves performance by storing downloaded data locally, reducing the need for repeated data downloads from the API. - Retrieving Session Data: The
session = fastf1.get_session(2023, 'Abu Dhabi', 'R')
line fetches the session data for the 2023 Abu Dhabi Grand Prix race ('R' stands for Race).session.load()
loads the data into memory. - Accessing Race Control Messages:
session.race_control_messages
is a DataFrame containing all race control messages for the selected session. These messages include information about penalties, track conditions, and other race-related notifications. - Using
loc
for Data Selection:messages = session.race_control_messages.loc[:, ['Time', 'Message']]
uses the.loc
method to select specific columns ('Time' and 'Message') from the race control messages DataFrame. The colon:
indicates that all rows are included, while['Time', 'Message']
specifies the columns to be selected. - Output: The
print(messages)
statement displays the DataFrame, which includes the time each message was issued and the message content.
Time Message
0 2023-11-26 12:10:01 GREEN LIGHT - PIT EXIT OPEN
1 2023-11-26 12:20:01 PIT EXIT CLOSED
2 2023-11-26 12:23:35 DOUBLE YELLOW IN TRACK SECTOR 12
3 2023-11-26 12:23:38 CLEAR IN TRACK SECTOR 12
4 2023-11-26 12:45:08 RISK OF RAIN FOR F1 RACE IS 0%
5 2023-11-26 12:57:05 DRS DISABLED
6 2023-11-26 13:03:26 GREEN LIGHT - PIT EXIT OPEN
7 2023-11-26 13:06:30 DRS ENABLED
8 2023-11-26 13:11:34 CAR 3 (RIC) TIME 1:31.326 DELETED - TRACK LIMI...
9 2023-11-26 13:14:08 TURN 7 INCIDENT INVOLVING CARS 24 (ZHO) AND 23...
10 2023-11-26 13:14:56 TURN 7 INCIDENT INVOLVING CARS 2 (SAR) AND 20 ...
11 2023-11-26 13:15:56 CAR 23 (ALB) TIME 1:33.560 DELETED - TRACK LIM...
12 2023-11-26 13:15:57 CAR 2 (SAR) TIME 1:33.582 DELETED - TRACK LIMI...
13 2023-11-26 13:16:05 CAR 55 (SAI) TIME 1:31.175 DELETED - TRACK LIM...
14 2023-11-26 13:17:24 FIA STEWARDS: TURN 7 INCIDENT INVOLVING CARS 2...
15 2023-11-26 13:18:08 CAR 4 (NOR) TIME 1:30.613 DELETED - TRACK LIMI...
16 2023-11-26 13:18:43 CAR 16 (LEC) TIME 1:30.609 DELETED - TRACK LIM...
17 2023-11-26 13:19:10 FIA STEWARDS: TURN 7 INCIDENT INVOLVING CARS 2...
18 2023-11-26 13:20:02 CAR 2 (SAR) TIME 1:32.038 DELETED - TRACK LIMI...
19 2023-11-26 13:20:28 CAR 27 (HUL) TIME 1:32.002 DELETED - TRACK LIM...
20 2023-11-26 13:21:59 CAR 24 (ZHO) TIME 1:32.298 DELETED - TRACK LIM...
21 2023-11-26 13:24:53 CAR 44 (HAM) TIME 1:31.432 DELETED - TRACK LIM...
22 2023-11-26 13:24:59 CAR 18 (STR) TIME 1:31.693 DELETED - TRACK LIM...
23 2023-11-26 13:25:11 CAR 23 (ALB) TIME 1:31.655 DELETED - TRACK LIM...
24 2023-11-26 13:26:41 CAR 81 (PIA) TIME 1:30.649 DELETED - TRACK LIM...
25 2023-11-26 13:27:04 TURN 6 INCIDENT INVOLVING CARS 44 (HAM) AND 10...
26 2023-11-26 13:27:40 CAR 22 (TSU) TIME 1:30.901 DELETED - TRACK LIM...
27 2023-11-26 13:27:52 CAR 22 (TSU) TIME 1:31.081 DELETED - TRACK LIM...
28 2023-11-26 13:28:10 FIA STEWARDS: TURN 6 INCIDENT INVOLVING CARS 4...
29 2023-11-26 13:29:23 CAR 22 (TSU) TIME 1:31.228 DELETED - TRACK LIM...
30 2023-11-26 13:34:24 FIA STEWARDS: TURN 6 INCIDENT INVOLVING CARS 4...
31 2023-11-26 13:38:31 CAR 1 (VER) TIME 1:29.634 DELETED - TRACK LIMI...
32 2023-11-26 13:39:28 CAR 20 (MAG) TIME 1:51.422 DELETED - TRACK LIM...
33 2023-11-26 13:47:53 CAR 16 (LEC) TIME 1:29.556 DELETED - TRACK LIM...
34 2023-11-26 13:49:31 CAR 55 (SAI) TIME 1:29.700 DELETED - TRACK LIM...
35 2023-11-26 13:50:43 CAR 81 (PIA) TIME 1:30.082 DELETED - TRACK LIM...
36 2023-11-26 13:51:01 CAR 3 (RIC) TIME 1:32.484 DELETED - TRACK LIMI...
37 2023-11-26 13:51:51 CAR 4 (NOR) TIME 1:30.010 DELETED - TRACK LIMI...
38 2023-11-26 13:52:23 CAR 18 (STR) TIME 1:29.831 DELETED - TRACK LIM...
39 2023-11-26 13:53:47 CAR 14 (ALO) TIME 1:30.426 DELETED - TRACK LIM...
40 2023-11-26 13:59:26 CAR 23 (ALB) TIME 1:30.555 DELETED - TRACK LIM...
41 2023-11-26 13:59:51 CAR 23 (ALB) TIME 1:30.350 DELETED - TRACK LIM...
42 2023-11-26 13:59:59 BLACK AND WHITE FLAG FOR CAR 23 (ALB) - TRACK ...
43 2023-11-26 14:02:08 TURN 4 INCIDENT INVOLVING CARS 14 (ALO) AND 44...
44 2023-11-26 14:04:43 FIA STEWARDS: TURN 4 INCIDENT INVOLVING CARS 1...
45 2023-11-26 14:05:31 CAR 11 (PER) TIME 1:29.195 DELETED - TRACK LIM...
46 2023-11-26 14:08:35 INCIDENT INVOLVING CAR 44 (HAM) NOTED - PIT ST...
47 2023-11-26 14:09:13 CAR 10 (GAS) TIME 1:29.621 DELETED - TRACK LIM...
48 2023-11-26 14:11:07 CAR 10 (GAS) TIME 1:29.717 DELETED - TRACK LIM...
49 2023-11-26 14:11:35 FIA STEWARDS: INCIDENT INVOLVING CAR 44 (HAM) ...
50 2023-11-26 14:13:23 INCIDENT INVOLVING CAR 10 (GAS) NOTED - PIT ST...
51 2023-11-26 14:13:31 FIA STEWARDS: INCIDENT INVOLVING CAR 10 (GAS) ...
52 2023-11-26 14:14:22 TURN 6 INCIDENT INVOLVING CARS 4 (NOR) AND 11 ...
53 2023-11-26 14:14:57 CAR 4 (NOR) TIME 1:28.568 DELETED - TRACK LIMI...
54 2023-11-26 14:15:37 FIA STEWARDS: TURN 6 INCIDENT INVOLVING CARS 4...
55 2023-11-26 14:18:33 INCIDENT INVOLVING CARS 1 (VER), 2 (SAR), 24 (...
56 2023-11-26 14:19:14 FIA STEWARDS: 5 SECOND TIME PENALTY FOR CAR 11...
57 2023-11-26 14:19:51 FIA STEWARDS: INCIDENT INVOLVING CARS 1 (VER),...
58 2023-11-26 14:22:01 WAVED BLUE FLAG FOR CAR 20 (MAG) TIMED AT 18:2...
59 2023-11-26 14:23:22 WAVED BLUE FLAG FOR CAR 77 (BOT) TIMED AT 18:2...
60 2023-11-26 14:24:58 CAR 63 (RUS) TIME 1:30.038 DELETED - TRACK LIM...
61 2023-11-26 14:30:15 WAVED BLUE FLAG FOR CAR 24 (ZHO) TIMED AT 18:3...
62 2023-11-26 14:30:29 CHEQUERED FLAG
63 2023-11-26 14:40:35 INCIDENT INVOLVING CAR 23 (ALB) NOTED - PIT ST...
64 2023-11-26 14:40:42 FIA STEWARDS: INCIDENT INVOLVING CAR 23 (ALB) ...
By running this script, users can obtain a detailed log of all race control messages for a particular F1 race.
We Only Need Time Penalties
Since we're only interested in time penalties from the race control messages, we need to filter the messages to include only those relevant to our analysis. Let's add two more lines to the code.
import fastf1
import pandas as pd
pd.set_option('display.max_rows', None)
fastf1.Cache.enable_cache('cache_dir')
session = fastf1.get_session(2023,'Abu Dhabi','R')
session.load()
messages = session.race_control_messages.loc[:,['Time', 'Message']]
specific_string = 'SECOND TIME PENALTY'
filtered_df = messages[messages['Message'].str.contains(specific_string, na=False)]
print(filtered_df)
specific_string = 'SECOND TIME PENALTY'
: This line creates a variable namedspecific_string
and assigns it the value'5 SECOND TIME PENALTY'
. This string will be used to identify messages that contain time penalties.filtered_df = messages[messages['Message'].str.contains(specific_string, na=False)]
: This line filters themessages
DataFrame. We use thestr.contains
method to check each message for the presence of ourspecific_string
. Thena=False
parameter ensures that any NaN (Not a Number) values in the 'Message' column are treated as False during the filtering process. As a result,filtered_df
is a new DataFrame containing only the rows frommessages
where the 'Message' column contains the string 'SECOND TIME PENALTY'.
Time Message
56 2023-11-26 14:19:14 FIA STEWARDS: 5 SECOND TIME PENALTY FOR CAR 11...
By adding these lines to our script, we can effectively isolate just the time penalties from the race control messages.
Find All the Penalties Across a Season
In this section, we expand our script to find all the time penalties across the entire 2023 F1 season. This script iterates through each race event in the season and filters out the time penalty messages, similar to what we did for a single race but now on a season-wide scale.
import fastf1
import pandas as pd
import logging
logging.getLogger('fastf1').setLevel(logging.CRITICAL)
pd.set_option('display.max_rows', None)
fastf1.Cache.enable_cache('cache_dir')
schedule = fastf1.get_event_schedule(2023)
for index, row in schedule.iterrows():
track = row['Location']
session = fastf1.get_session(2023,track,'R')
session.load()
session_name = session.event['EventName']
print(session_name)
messages = session.race_control_messages
specific_string = 'SECOND TIME PENALTY'
filtered_df = messages[messages['Message'].str.contains(specific_string, na=False)]
for index, row in filtered_df.iterrows():
message = row['Message'].replace('FIA STEWARDS: ', '')
print(message)
print('\n')
- Setting Logging Level: The script begins by setting the logging level for
fastf1
toCRITICAL
withlogging.getLogger('fastf1').setLevel(logging.CRITICAL)
. This is done to minimize unnecessary logging output from thefastf1
library. - Retrieving Season Schedule:
schedule = fastf1.get_event_schedule(2023)
fetches the schedule for all events in the 2023 F1 season. This schedule includes information about each race, like location and date. - Iterating Over Each Event: The script uses a for loop (
for index, row in schedule.iterrows():
) to iterate over each event in the season schedule. For each event, it retrieves the race session data usingsession = fastf1.get_session(2023, track, 'R')
andsession.load()
. Here, 'R' stands for the Race session. - Printing Time Penalty Messages: Finally, for each event, the script iterates over the filtered DataFrame containing penalty messages. It prints each message, having removed the prefix 'FIA STEWARDS: ' for clarity, using
message = row['Message'].replace('FIA STEWARDS: ', '')
andprint(message)
. - Separating Events:
print('\n')
at the end of the outer loop adds a newline after processing each event, making the output more readable by separating the penalties for each race.
By running this script, you can comprehensively extract and list all time penalties issued during each race of the 2023 F1 season, providing a season-wide overview of penalties in an organized and readable format. Here is the output.
Bahrain Grand Prix
5 SECOND TIME PENALTY FOR CAR 31 (OCO) - INACCURATE GRID POSITION
10 SECOND TIME PENALTY FOR CAR 31 (OCO) - SERVING TIME PENALTY INCORRECTLY
5 SECOND TIME PENALTY FOR CAR 31 (OCO) - SPEEDING IN THE PIT LANE
5 SECOND TIME PENALTY FOR CAR 27 (HUL) - MULTIPLE TRACK LIMITS
10 SECOND TIME PENALTY FOR CAR 27 (HUL) - MULTIPLE TRACK LIMITS
Saudi Arabian Grand Prix
5 SECOND TIME PENALTY FOR CAR 14 (ALO) - INCORRECT STARTING LOCATION
10 SECOND TIME PENALTY FOR CAR 14 (ALO) - SERVING PENALTY INCORRECTLY
Australian Grand Prix
5 SECOND TIME PENALTY FOR CAR 55 (SAI) - CAUSING A COLLISION
Azerbaijan Grand Prix
Miami Grand Prix
5 SECOND TIME PENALTY FOR CAR 55 (SAI) - SPEEDING IN THE PIT LANE
Monaco Grand Prix
5 SECOND TIME PENALTY FOR CAR 27 (HUL) - CAUSING A COLLISION
5 SECOND TIME PENALTY FOR CAR 2 (SAR) - SPEEDING IN THE PIT LANE
5 SECOND TIME PENALTY FOR CAR 63 (RUS) - UNSAFE REJOIN
10 SECOND TIME PENALTY FOR CAR 27 (HUL) - SERVING PENALTY INCORRECTLY
Spanish Grand Prix
5 SECOND TIME PENALTY FOR CAR 22 (TSU) - FORCING ANOTHER DRIVER OFF THE TRACK
Canadian Grand Prix
5 SECOND TIME PENALTY FOR CAR 4 (NOR) - UNSPORTSMANLIKE BEHAVIOUR
Austrian Grand Prix
5 SECOND TIME PENALTY FOR CAR 44 (HAM) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 22 (TSU) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 31 (OCO) - UNSAFE RELEASE
5 SECOND TIME PENALTY FOR CAR 55 (SAI) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 23 (ALB) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 21 (DEV) - FORCING ANOTHER DRIVER OFF THE TRACK
5 SECOND TIME PENALTY FOR CAR 10 (GAS) - TRACK LIMITS
10 SECOND TIME PENALTY FOR CAR 22 (TSU) - 7 TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 2 (SAR) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 20 (MAG) - TRACK LIMITS
British Grand Prix
5 SECOND TIME PENALTY FOR CAR 18 (STR) - CAUSING A COLLISION
Hungarian Grand Prix
5 SECOND TIME PENALTY FOR CAR 24 (ZHO) - CAUSING A COLLISION
5 SECOND TIME PENALTY FOR CAR 16 (LEC) - SPEEDING IN THE PIT LANE
Belgian Grand Prix
Dutch Grand Prix
10 SECOND TIME PENALTY FOR CAR 40 (LAW) - IMPEDING
5 SECOND TIME PENALTY FOR CAR 10 (GAS) - SPEEDING IN THE PIT LANE
5 SECOND TIME PENALTY FOR CAR 22 (TSU) - CAUSING A COLLISION
5 SECOND TIME PENALTY FOR CAR 11 (PER) - SPEEDING IN THE PIT LANE
Italian Grand Prix
5 SECOND TIME PENALTY FOR CAR 63 (RUS) - LEAVING THE TRACK AND GAINING AN ADVANTAGE
5 SECOND TIME PENALTY FOR CAR 44 (HAM) - CAUSING A COLLISION
5 SECOND TIME PENALTY FOR CAR 2 (SAR) - CAUSING A COLLISION
Singapore Grand Prix
5 SECOND TIME PENALTY FOR CAR 14 (ALO) - FAILING TO FOLLOW RACE DIRECTORS INSTRUCTIONS – CROSSING THE LINE AT PIT ENTRY
Japanese Grand Prix
5 SECOND TIME PENALTY FOR CAR 2 (SAR) - CAUSING A COLLISION
5 SECOND TIME PENALTY FOR CAR 11 (PER) - SAFETY CAR INFRINGEMENT
5 SECOND TIME PENALTY FOR CAR 11 (PER) - CAUSING A COLLISION
Qatar Grand Prix
10 SECOND TIME PENALTY FOR CAR 27 (HUL) - INCORRECT STARTING LOCATION
5 SECOND TIME PENALTY FOR CAR 11 (PER) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 11 (PER) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 18 (STR) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 10 (GAS) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 10 (GAS) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 23 (ALB) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 23 (ALB) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 18 (STR) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 10 (GAS) - TRACK LIMITS
5 SECOND TIME PENALTY FOR CAR 11 (PER) - TRACK LIMITS
United States Grand Prix
5 SECOND TIME PENALTY FOR CAR 23 (ALB) - TRACK LIMITS
Mexico City Grand Prix
São Paulo Grand Prix
Las Vegas Grand Prix
LAP 1 TURN 1 INCIDENT 5 SECOND TIME PENALTY FOR CAR 1 (VER) - FORCING ANOTHER DRIVER OFF THE TRACK
5 SECOND TIME PENALTY FOR CAR 63 (RUS) - CAUSING A COLLISION
Abu Dhabi Grand Prix
5 SECOND TIME PENALTY FOR CAR 11 (PER) - CAUSING A COLLISION
Closing Up
In conclusion, by using the fastf1 Python library, we've successfully navigated through the process of extracting time penalties from the 2023 Formula 1 season. This method not only gives us a detailed view of penalties in individual races but also offers a season-wide perspective, all with a few lines of code.