The Impact of Match Duration on Player Performance in WTA Grand Slam Matches (2018–2022)

Author

Ash Ibasan

A collage showcasing the four Grand Slam venues from left to right, top to bottom: Australian Open (Melbourne Park, hard court), French Open (Roland Garros, clay court), Wimbledon (All England Club, grass court), US Open (Arthur Ashe Stadium, hard court). Photo Credit: Bleacher Report)

Introduction

Growing up playing tennis, I’ve always wondered how the length of a match affects a player’s ability to perform at their peak. For myself, as the match lingered on, my overall performance suffered greatly, mentally and physicall. Tennis demands an incredible combination of physical endurance and mental focus, and longer matches often push even the most skilled athletes to their limits. I’ve always been curious about these questions: since casual, recreational players like me tire out after a while, is that also the case for those playing at the professional level? Specifically, at the elite level, does the duration of a match impact specific performance indicators, like hitting aces or saving break points?

For this analysis, I will focus on WTA Grand Slam matches played between 2018 and 2022, and I hope to find out whether longer matches influence aspects of a player’s game, such as serving precision or defensive performance by examining match duration along with performance metrics.

Dataset source

The data comes from Jeff Sackmann, a software developer known for building research-quality tennis databases. Uploaded in SCORE Network, he compiles detailed records of WTA singles matches, including match statistics and player rankings. Each entry in the dataset provides information about both players’ performance, such as aces, double faults, and break points saved, and the dataset aggregates official WTA match statistics and biographical details.

Variables explored

  • minutes - total match duration (independent variable)

  • w_ace - number of aces hit by winning player

  • w_df - double faults committed by winning player

  • w_bpSaved - break points saved by winning player

Questions to think about

  • Does the length of a match affect how many aces a player hits?

  • Are players more prone to double faults in longer matches?

  • Do longer matches challenge players’ defensive ability, as seen in their ability to save break points?

Data cleaning and prep

In this step, I loaded the necessary libraries and the dataset to analyze for this project. Then, I cleaned the dataset to focus on key variables relevant to my analysis: minutes (match duration), w_ace (number of aces), w_df (double faults), w_bpSaved (break points saved), and surface (type of court). Missing values were replaced with the median for each numerical column rather than dropping rows, to make sure there is no data that was unnecessarily removed. Approaching the cleaning and prep this way maintains the integrity of the dataset while addressing incomplete values. Finally, I verified the cleaning process by checking for any remaining missing values and displaying the cleaned data for inspection.

Load libraries and dataset

library(tidyverse)
Warning: package 'tidyverse' was built under R version 4.4.1
Warning: package 'ggplot2' was built under R version 4.4.1
Warning: package 'tibble' was built under R version 4.4.1
Warning: package 'tidyr' was built under R version 4.4.1
Warning: package 'readr' was built under R version 4.4.1
Warning: package 'purrr' was built under R version 4.4.1
Warning: package 'dplyr' was built under R version 4.4.1
Warning: package 'stringr' was built under R version 4.4.1
Warning: package 'forcats' was built under R version 4.4.1
Warning: package 'lubridate' was built under R version 4.4.1
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(plotly)  # interactivity
Warning: package 'plotly' was built under R version 4.4.1

Attaching package: 'plotly'

The following object is masked from 'package:ggplot2':

    last_plot

The following object is masked from 'package:stats':

    filter

The following object is masked from 'package:graphics':

    layout
wta_data <- read_csv("wta-grand-slam-matches-2018to2022.csv")
Rows: 2413 Columns: 38
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (12): tourney_name, surface, winner_seed, winner_name, winner_hand, winn...
dbl (26): tourney_date, winner_ht, winner_age, loser_ht, loser_age, minutes,...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Inspect dataset by displaying first few rows

head(wta_data)
# A tibble: 6 × 38
  tourney_name  surface tourney_date winner_seed winner_name         winner_hand
  <chr>         <chr>          <dbl> <chr>       <chr>               <chr>      
1 ROLAND GARROS Clay        20180528 1           Simona Halep        R          
2 ROLAND GARROS Clay        20180528 <NA>        Taylor Townsend     L          
3 ROLAND GARROS Clay        20180528 <NA>        Bethanie Mattek Sa… R          
4 ROLAND GARROS Clay        20180528 <NA>        Andrea Petkovic     R          
5 ROLAND GARROS Clay        20180528 24          Daria Saville       R          
6 ROLAND GARROS Clay        20180528 <NA>        Bernarda Pera       L          
# ℹ 32 more variables: winner_ht <dbl>, winner_ioc <chr>, winner_age <dbl>,
#   loser_seed <chr>, loser_name <chr>, loser_hand <chr>, loser_ht <dbl>,
#   loser_ioc <chr>, loser_age <dbl>, score <chr>, round <chr>, minutes <dbl>,
#   w_ace <dbl>, w_df <dbl>, w_svpt <dbl>, w_1stIn <dbl>, w_1stWon <dbl>,
#   w_2ndWon <dbl>, w_SvGms <dbl>, w_bpSaved <dbl>, w_bpFaced <dbl>,
#   l_ace <dbl>, l_df <dbl>, l_svpt <dbl>, l_1stIn <dbl>, l_1stWon <dbl>,
#   l_2ndWon <dbl>, l_SvGms <dbl>, l_bpSaved <dbl>, l_bpFaced <dbl>, …

Data cleaning and wrangling

wta_clean <- wta_data %>%
  select(minutes, w_ace, w_df, w_bpSaved, surface) %>%   # choose relevant variables
  
  mutate( # replace missing values with median for numerical columns
    minutes = ifelse(is.na(minutes), median(minutes, na.rm = TRUE), minutes),
    w_ace = ifelse(is.na(w_ace), median(w_ace, na.rm = TRUE), w_ace),
    w_df = ifelse(is.na(w_df), median(w_df, na.rm = TRUE), w_df),
    w_bpSaved = ifelse(is.na(w_bpSaved), median(w_bpSaved, na.rm = TRUE), w_bpSaved)
  )

summary_duration <- wta_clean %>%
  summarize(avg_duration = mean(minutes, na.rm = TRUE))

colSums(is.na(wta_clean)) # make sure missing values were handled
  minutes     w_ace      w_df w_bpSaved   surface 
        0         0         0         0         0 
summary_duration # print the average match duration
# A tibble: 1 × 1
  avg_duration
         <dbl>
1         95.8

View cleaned data

head(wta_clean)
# A tibble: 6 × 5
  minutes w_ace  w_df w_bpSaved surface
    <dbl> <dbl> <dbl>     <dbl> <chr>  
1      94     0     1         3 Clay   
2      84     2     4         7 Clay   
3      95     3     1         5 Clay   
4     102     1     2         3 Clay   
5     162     1    17         7 Clay   
6      64     5     2         5 Clay   

Linear regression

In this step, I’ll analyze whether match duration (minutes) influences the number of aces (w_ace) by performing a linear regression. Let’s look at their relationship, view the regression summary.

Regression model

lm_model <- lm(w_ace ~ minutes, data = wta_clean) # performing linear regression: match duration (minutes) vs. number of aces (w_ace)
summary(lm_model) # regression results

Call:
lm(formula = w_ace ~ minutes, data = wta_clean)

Residuals:
   Min     1Q Median     3Q    Max 
-4.643 -2.314 -0.617  1.546 19.928 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 2.427429   0.205344  11.821  < 2e-16 ***
minutes     0.011662   0.002041   5.715 1.23e-08 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 3.078 on 2411 degrees of freedom
Multiple R-squared:  0.01337,   Adjusted R-squared:  0.01296 
F-statistic: 32.66 on 1 and 2411 DF,  p-value: 1.233e-08

Equation (given)

w_ace = β 0 ​ +β 1 ​ ⋅ minutes + ϵ

Linear regression equation explanation

  • w_ace -number of aces by the winning player (dependent variable).

  • minutes - match duration (independent variable).

  • β₀ - intercept, the baseline number of aces when match duration is 0.

  • β₁ - slope, the increase/decrease in the number of aces for every 1-minute increase in match duration.

  • ε - residual (error term)

Results explanation (final equation)

w_ace = 2.43 + 0.012 ⋅ minutes

For every additional minute of match duration, the number of aces increases by 0.012 on average. The p-value, 1.23e-08, indicates the relationship is statistically significant. The adjusted r-squared value, 0.013, shows that match duration explains 1.3% of the variability in the number of aces. In conclusion, while the duration of matches has a significant impact on aces, the low r-squared suggests other external factors that influences the results, like player skill or the differing court surfaces played.

Visualizations

Scatterplot with regression line

This scatter plot shows the relationship between match duration and number of aces, with points colored by the court surfaces - clay, grass, and hard. The regression line shows a positive trend; as match duration increases, the number of aces generally increases. However, there are visible variations across surfaces, which suggests surface type may also influence ace counts.

scatter_plot <- ggplot(wta_clean, aes(x = minutes, y = w_ace)) +
  geom_point(aes(color = surface), alpha = 0.8, size = 2.5) + 
  geom_smooth(method = "lm", color = "white", se = TRUE, size = 1.2) +
  scale_color_manual(values = c(
    "Clay" = "#FF6347", 
    "Grass" = "#FFD700",   
    "Hard" = "#00BFFF"    
  )) +
  labs(
    title = "Match Duration Impact on Aces by Surface Type",
    x = "Match duration in minutes",
    y = "Number of aces by winner",
    color = "Surface Type",
    caption = "Source: Jeff Sackmann's WTA Dataset"
  ) +
  theme_minimal() +
  theme(
    panel.background = element_rect(fill = "#2E8B57"),  
    plot.background = element_rect(fill = "#2E8B57"),  
    panel.grid.major = element_line(color = "beige", size = 0.4),  
    panel.grid.minor = element_blank(),
    text = element_text(color = "white"),
    plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
    axis.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 10),
    legend.background = element_rect(fill = "#2E8B57", color = NA),
    legend.text = element_text(color = "beige"),
    legend.title = element_text(color = "beige", face = "bold")
  )
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
ℹ Please use the `linewidth` argument instead.
# plotly for interactivity
interactive_scatter <- ggplotly(scatter_plot)
`geom_smooth()` using formula = 'y ~ x'
interactive_scatter

Boxplot of double faults by surface types

The boxplot compares the distribution of double faults by the winning player across surface types. Clay courts show a wider range of double faults, indicating more variability in serving performance on this surface, while grass and hard courts display tighter distributions, suggesting more consistent serving outcomes. Outliers on clay courts might reflect the challenge of adjusting to its slower pace.

boxplot_surface <- ggplot(wta_clean, aes(x = surface, y = w_df, fill = surface)) +
  geom_boxplot(alpha = 0.8, outlier.color = "red", outlier.shape = 16, size = 0.8) +  
  scale_fill_manual(values = c(
    "Clay" = "#FF7F50",  
    "Grass" = "#FFB347",  
    "Hard" = "#DB7093"   
  )) +
  labs(
    title = "A Look at Double Faults Across Surfaces",
    x = "Surface Type",
    y = "Number of Double Faults",
    fill = "Surface",
    caption = "Source: Jeff Sackmann's WTA Dataset"
  ) +
  theme_minimal() +
  theme(
    panel.background = element_rect(fill = "#2E8B57"),  
    plot.background = element_rect(fill = "#2E8B57"),   
    panel.grid.major = element_line(color = "beige", size = 0.5),  
    panel.grid.minor = element_blank(),
    text = element_text(color = "white"), 
    plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
    axis.title = element_text(size = 12, face = "bold"),
    axis.text = element_text(size = 10),
    legend.background = element_rect(fill = "#2E8B57", color = NA),
    legend.text = element_text(color = "beige"),
    legend.title = element_text(color = "beige", face = "bold")
  )

boxplot_surface # display plot

Conclusion

To answer the initial question, “does the duration of a match impact specific performance indicators, like hitting aces or saving break points at the elite level?”, the results suggest a nuanced relationship.

Analyzing WTA Grand Slam matches from 2018 to 2022 through this project has been fascinating, not just because I grew up with tennis but also because of my curiosity about the physical demands on elite players during long matches.

Tennis requires a blend of endurance, skill, and mental sharpness, and it is clear that even small changes in match duration can influence performance metrics like aces, double faults, and break points saved.

From my linear regression analysis, I found that for every additional minute a match goes on, there is a slight increase in the number of aces hit. While the relationship is statistically significant, the low R-squared value tells me that match duration alone is not the whole story; factors like player skill, surface type, and strategy likely play as big of a role, which brings it to the bigger picture: tennis has evolved. Players have had to adapt to the increasingly physical nature of the game.

Research highlights how tennis matches, particularly on the men’s side, are getting longer, sometimes pushing beyond the three-hour mark. Even in women’s matches, marathon matches are no longer uncommon. Beatriz Haddad Maia’s 3-hour, 51-minute match at Roland Garros (French Open) demonstrates just how grueling the game can be (Pluim et al. 3). These days, players are fitter, faster, and better trained than ever before, with support teams focusing on nutrition, recovery, and performance optimization (Pluim et al. 4).

At the same time, surfaces have slowed down, and rally lengths have increased. Clay courts demand endurance and patience, leading to longer matches and higher variability in key performance indicators. Data from Jeff Sackmann’s dataset from SCORE Network and his GitHub repository (cross-referenced) shows evidence that surfaces like clay can contribute to longer, more demanding matches (“WTA Grand Slam Matches”). The shift, where courts, equipment, and training have all aligned to push players to their limits, reminds me of my desire to understand if players can maintain precision and focus under these taxing conditions.

While I focused primarily on match duration and its relationship with aces, break points saved, and double faults, there are areas I wish I had more time to explore. For example, I wanted to explore of the dataset by incorporating player fatigue, serve speeds, or head-to-head records could provide a deeper look into how performance declines (or holds steady) over extended matches. I also wished to have more time to analyze the court performance individually as the players specialize on different surfaces, which can affect the dataset numbers drastically. For example, a clay specialist’s numbers might skew significantly compared to a grass court player, and analyzing this deeper would add more insight to the dataset.