Expecting events

Understanding expected events in football: xG and xGOT

Abraar Ahmed
14 min readJan 16, 2025

In Fantasy Premier League (FPL) during the English Premier League (EPL) 2024/25 season, there is a maxim — “When is doubt, always captain Salah.” This had me rethinking an idea that crossed my mind many moons ago of computing the probability of the occurrence of an event in football and while watching matches observing if an expectation comes to fruition. The motivating factor for this thought were the charged debates of the quality of player and team performances with friends. In the intervening years, there has been an analytics revolution in the sport. This has gone well beyond the odds of a big event like goal, assist, or foul happening to the development of specialized statistics to translate qualities like possession, attacking play, and control into numbers that can be analyzed. For those with a deep interest in sports statistics, it might seem like a repurposing of the concept of Sabermetrics. While I have no specialized understanding of baseball, it was not difficult to glean that each player’s actions in each game can be isolated and organized into self contained events due to the design of the sport. Football, on the other hand, is more free-flowing and the isolation of player actions in each match did not have similar natural bookends. While there are similarities in the spirit of analyzing these sports, there can be no doubt that each has its own art, impetus, methods, and cast of characters.

My team isn’t in the EPL, yet I’m ploughing through its numbers because of this.

Background

As alluded to earlier, my revitalized interest in moneyball for football comes from stepping back into the world of FPL by agreeing to co-manage a team with a friend. Most of my work with data in the last few years has been on language models and my interest in football has been sated by following my favorite team which isn’t in the Premier League so to get a grip on what has transpired tactically in the league, I began listening to a bunch of dudes with microphones. Jokes aside, programs like The Double Pivot Podcast and The Athletic FC Tactics Podcast feature deep football tactics thinkers like the authors of Expecting Goals and Zonal Marking. A recurring pattern when listening to them speak is of players over or under performing expected events where events are defined as incidents that increase or decrease the chance of a team winning the match. This often presents itself to laymen in the expected goals (xG) statistic on match broadcasts, sometimes stated by commentators and half time talking heads or at other times in chyrons during the match. To better understand it, I decided to explore open data and attempt to implement a couple of simple models including xG. Fortunately, Statsbomb has select free data that one can experiment with before deciding to pay for up to date data from their API. What’s more fortunate is that they’ve made the EPL 2015/16 season data available. Yes, the one with that historic run of a certain team promoted to the league only a season before, making this endeavor even more exciting!

5,000:1 odds, but not impossible.

Expected Goals

At the end of a game, it is relatively easy to acquire statistics like shots, shots on goal, and number of goals and to use these to compute ex post odds of scored goals. It is also possible to go a step further and take the history of the two participants’ matches to compute the odds of one scoring against the other. The elegance of xG as a metric lies in being a measure of the quality of each chance taken; given certain features of a shot, the statistical probability of a goal being scored from it.

Feature explanation and visual analysis

Summarization of Statsbomb’s dataset shows that for the season, 988 goals were scored off 9,908 shots taken by all teams in the league. This is a dataset of event data, not summary statistics or player tracking. Each of the shots in it has a number of features associated with the shot like technique, body part used, and play pattern. I can plot these to begin developing intuitions of what a model might assign as the effect of the feature on the expectation of a shot being converted. At a surface level, I see that there is an order of magnitude count difference between shots that resulted in a goal and those that did not.

An order of magnitude difference.
There it is, an order of magnitude.

When I dig further into the data, I observe that there are features which identify if a set piece resulted in a goal or it was produced in open play. The set pieces are further broken down into sub types and play patterns. Play pattern is an interesting feature in its own right as it encodes an aspect of the formation not explicit in the data; the original formation implemented in regular play or an alternative one utilized during a counter or yet another special one designed for free/corner kicks. I highlight the last of these because of the recent ubiquity of set piece specialty coaches in the EPL. Game playing or watching experience tells us that some set pieces increase the chance of a shot being converted and shot quality has a different feel based on the pattern of play. The most obvious of these is a shot taken from the penalty spot or goal generated from controlled possession. A model should be able to quantify, a good model should be able to explain. That is the path that I’m on.

Again, an order of magnitude difference.
No way, an order of magnitude!

Surely tracking data has more features for every chance created providing more context to the situation. Additionally, it is likely a better source to profile a player with. Nevertheless, given the fact that every match event is logged in the dataset, for a creative mind interested in the sport there are avenues of synthetic feature generation to answer unique questions about a shot. For example, one can identify the height of passes that immediately precede a goal to generate features that would likely have an effect on the quality of shot one way or another. Or even how much time has elapsed since the pass before the shot was taken. Another example is to identify if players in wing positions of a build up cut into the field to make an attempt at goal, what effect does that movement have on shot quality. In fact, I generate these features for modeling.

Here we go again, an order of magnitude.
Synthetic data comes in many shapes.

Using underlying numbers like the x and y values representing the position that a shot was taken from on a 2-dimensional pitch and where it ended, I can derive composite data like the angle and distance the shot was fired from and whether it was on or off target. Looking at the shot map of the entire season, one gets the sense that the distance from goal of a shot has an effect on the quality of it. Could there be an effect of the angle the shot is taken from on its quality as well?

Some absolute bangers along the edges of that shot map!
Closer is indeed better.

It is difficult to discern the effect of the angle simply from the shot map. On the other hand, computing the distance of each shot from the goal and using a violin plot to visualize them shows us that there’s a clear difference between the groups of shots that result in a goal and that do not. Our sense that the distance has an effect is validated with the the plot of shots resulting in goal peaking at a shorter distance than the shots not resulting in goal which also seem to have a much longer tail representing a greater distance. I repeat this process; calculate the angle and generate a violin plot. As the computation of angle is a little more complex than that for distance, I’ll include the code here.

import math
import numpy as np

def calculate_angle(x: float, y: float) -> float:
"""
Equations for angle calculation.
"""
# 36 and 44 are locations of each goal post
post_0 = [120, 44]
post_1 = [120, 36]
p = [x, y]
v0 = np.array(post_0) - np.array(p)
v1 = np.array(post_1) - np.array(p)
theta = math.atan2(np.linalg.det([v0, v1]), np.dot(v0, v1))
angle = abs(np.degrees(theta))
return angle
There is a marginal gain to taking the shot from a higher angle up to a point.

In the Statsbomb dataset is included the xG calculated by their analytics organization. I have retained that xG per shot in the dataset to enable a comparison of my model output against, when it has been developed. The knock on effect is that I can see the difference in Statsbomb xG for other features, as well. Observing the average angle and distance, those shots that result in goal are typically from a shorter distance and a slightly wider angle. The Statsbomb xG is directionally correct on this. This manner of feature analysis can be done for other provider provided features or composite features, namely whether the shot was taken under pressure or it was taken in a time crunch which is determined as being attempted after the 85th minute of a match.

Greater angle, shorter distance, and boom!

xG model elucidation and relative performance

With the features available to us, it is feasible to develop a logistic regression model to analyze the quality of each shot. There possibly are other models to fit the features to better relate the independent variables to the dependent variable or features to shot result, but I won’t explore those in this post as this is a simple explainer model to get a handle on the concept of xG. Upon training the regression model and applying it to the data at hand, I retrieve a shot by shot xG value. To differentiate between the two sets of xG values, I’ll refer to the one that came with the dataset as Statsbomb xG and the one that I’ve produced as model xG. Post model xG generation, I run a Pearson pairwise correlation between each of the features and the xG value which provides us a quantified understanding of the effect of the feature on the model xG.

Correlations

distance -0.552772
sub_type_name_Open Play -0.180225
sub_type_name_Free Kick -0.078337
finesse_side -0.076876
play_pattern_name_From Free Kick -0.059351
pass_height_name_Ground Pass -0.054835
play_pattern_name_From Corner -0.050167
play_pattern_name_From Throw In -0.037182
technique_name_Half Volley -0.029927
play_pattern_name_Regular Play -0.027590
under_pressure -0.027040
play_pattern_name_From Goal Kick -0.013780
technique_name_Normal -0.007844
play_pattern_name_From Keeper -0.007759
sub_type_name_Corner -0.007238
play_pattern_name_From Kick Off -0.002049
time_crunch 0.001262
technique_name_Volley 0.004434
technique_name_Overhead Kick 0.012231
pass_height_name_Low Pass 0.026912
technique_name_Diving Header 0.033054
pass_height_name_High Pass 0.037183
technique_name_Lob 0.042165
header 0.045603
play_pattern_name_From Counter 0.084855
technique_name_Backheel 0.085794
time_since_pass 0.150383
play_pattern_name_Other 0.547909
sub_type_name_Penalty 0.573397
angle 0.681792
xg_y 1.000000

Studying the results of the correlation, I’ll provide a few takeaways that will assist in reading these numbers:

  • To ground our understanding in something we saw visually above, we note that greater distance of a shot does indeed have a negative correlation with the expectation of it being scored.
  • Considering the sub type, we notice that intuition holds up. Penalties have the highest positive correlation to xG while shots taken in open play have the highest negative correlation.
  • Ranking play patterns not placed in the ambiguous bucket termed other, we see that shooting while on a counter has the highest correlation to xG while shooting from a free kick has the lowest correlation.
  • Reviewing the correlations of features that I created for the xG model; some have a positive correlation like time since pass, others have a negative correlation like finesse side, and yet others have almost no correlation like time crunch. From an in match perspective, this means that when players take a moment to settle on the ball after a pass they typically generate a shot with higher xG, when players cut in from the wing to shoot they typically generate a shot with lower xG, and chances taken in the minutes past the 85th don’t have a discernible effect on shot xG.

For those not in the know, the coefficient of determination or r-squared (r2) is the variation in expected goals that is predictable from the independent features. Generally, a higher value is better and by applying this metric we observe that the explainer model is effective but the Statsbomb model outpaces it. For the purpose of this piece, I’ll use it anyway but it sets a benchmark for further development.

r2 Comparison

explainer model xG 0.1605
statsbomb xG 0.2063

The next topic to address with regards to per shot xG is how this translates to understanding team performance. Summating the per shot value of a team over a time period returns the expected goals over that period. The period can be any logical block like match or even season to capture the match xG or season xG respectively of a team. Hindsight is 20/20 and from the vantage point of 2025 we know that Leicester City Football Club won the league title in the season under consideration. Can we quantify if LCFC over or under performed their xG? Sure we can. First, I get the season xG in the manner outlined above, then add all the goals scored by each team over the season, and finally get the team-wise difference between the season model xG and the actual goals scored by the team. I did this calculation for home and away performances of each team, too.

12th man helping LCFC sneak into over-performance at home?
LCFC under-performance away, but only by a little.

Home and away, LCFC has had different types of performance. At home, they’ve slightly over-performed their xG sneaking into the top 10 of home over-performers but away they have under-performed their xG by ending up in the bottom 6. Incredibly, at the aggregate level across home and away, LCFC slightly under-perform their xG but their sheer count of goals is quite high. Not to miss the forest for the trees, both LCFC’s goals scored and their model xG are top tier numbers for the season. An expected event that would enhance this goal based view of performance is computation of Expected Goals Against (xGA). That is out of scope for this piece, but something I will keep in mind for active seasons model development.

Overall, LCFC slightly underperforms xG but scores a ton anyway.

Another comparison for future analysis that immediately comes to mind is to split xG along the lines of game state — team leading, team trailing, or teams level during a match. Fascinating findings all round, and they’ve shown to open more expected events avenues to paint a comprehensive picture. The value of different expected events metrics is in slicing and dicing them in a manner that helps us either better understand the game or find inefficiencies in performance so as to mitigate them. To this end, we’ll explore another expected events metric and in a twist, this one will focus on players.

Expected Goals on Target

The xG model I’ve discussed so far is a pre-shot model whereas Expected Goals on Target (xGOT) is a post-shot model. For calculating the expectation of this event, the biggest factor to account for is the location the ball ends up at after the shot is taken due to which it is also called Post Shot Expected Goals. From the goal map below, we can infer that the highest xGOT is from low shots into either corner followed by high shots into a top corner with the lowest being from those straight down the middle. It makes sense to include the distance the ball traversed and angle of arrival to get the whole picture of the finishing ability of the player, so I did that.

If you squint, the red cluster in the middle looks like a goalkeeper flying sideways.

In the Statsbomb event data, we have the starting x and y coordinates using which I calculated the angle and distance traversed by each shot. Also included is the end y and z coordinates which allow me to compute the end location of each shot. The tricky part of the latter process is to estimate where the posts and crossbar are but this is managed by filtering on post for outcome name across all shots to estimate the y and z coordinates of the boundaries of the face of goal. With these features, the mechanics of development of the xGOT explainer model are not much different to those of the xG explainer model. The r2 value of this model is 0.18 which is higher than the xG model. xGOT per player is aggregated for the season in the same manner that xG was aggregated for teams.

What winning a Golden Boot in the EPL looks like.

While the season’s phenomenal performances rightly raised the profile of Leicester City attackers Jamie Vardy and Riyad Mahrez, it’s important to remember that Harry Kane won the EPL Golden Boot. The sheer number of shots that he took in the season was incredible, 40 more than Vardy or Aguero! Nevertheless, all three placed less than half of their shots on target. Kane’s xGOT over the season was 22.89 and he finished in the expected range by scoring a total of 25.

Aguero was top in over-performance, but LCFC had more than one in the top 5!

Aguero and Vardy were strikingly similar in numbers even though they have different styles of play. They took the same number of total shots and scored the same number of goals while Vardy was off target in shooting by a couple more which resulted in him having a fractionally higher xGOT. In the end, that was what helped Aguero pip him in over-performance. That said, both players greatly over-perform their xGOT, so much so that they’re the top two in over-performance! These numbers show that there is truth in arguments made for Vardy performing at the same level as Aguero, at least through that season.

What winning hearts and a title looks like.
What over-performance looks like.

Moneyball isn’t just about picking a team from a spreadsheet but a much wider change in the thinking of team selection catalyzing a fusion of numbers, performance, and news. There are other expected events that can be computed in a rolling game-week by game-week basis like Expected Assists, Expected Goal Involvement, Expected Goals Conceded, and many more given player position and team balance that one is aiming to maintain for their team. For my purpose which is to build a successful FPL squad, there are obvious constraints enforced by the league namely a cost cap, total of 2 goalkeepers, 5 defenders, 3 forwards, and the rest midfielders. Within those bounds, there is much strategy that I need to hammer out. This quick dive shows that it is valuable to seek out players who meet high quantified expectations or over-perform expected events when set against player cost, and has convinced me that this is a new weapon I should add to my arsenal. One day, when football tracking data is more available, I would like to deploy more advanced algorithms to assist with predicting manager and team behavior for FPL squad selection.

This year though, all eyes are on Slot’s Liverpool and the unexpected dip in Guardiola’s Manchester City. But I ask you dear reader, do you think Nottingham Forest will continue their fairytale run? How many of their players do you have in your FPL squad?

Top 4, inevitable?

In addition to FPL and being able to be conversant in this shift in football, other interesting pieces in this domain have drawn me towards this exploration. I’ll highlight several worth a read here: research on football set-pieces, football prediction methodology, and the effect of AI in football.

--

--

Abraar Ahmed
Abraar Ahmed

Written by Abraar Ahmed

Learning machines, unfinished books, technology dreams, incomplete essays, adventure highs, half-baked experiments, and absorbing the human condition.

No responses yet