Article by Ben Griffis
This article takes an analytical look at player attacking performance in France’s Ligue 1 so far this season. I collected data (from understat.com using Python code) on April 19th, after every team played 33 games. Lille currently sit atop the league with 70 points, one point above Paris Saint-Germain (PSG). Monaco follow closely with 68. Below is the current table.
Position | Team | Played | Wins | Draws | Losses | Points |
1 | Lille | 33 | 20 | 10 | 3 | 70 |
2 | Paris Saint-Germain | 33 | 22 | 3 | 8 | 69 |
3 | Monaco | 33 | 21 | 5 | 7 | 68 |
4 | Lyon | 33 | 19 | 10 | 4 | 67 |
5 | Lens | 33 | 14 | 11 | 8 | 53 |
6 | Marseille | 33 | 14 | 10 | 9 | 52 |
7 | Rennes | 33 | 14 | 9 | 10 | 51 |
8 | Montpellier | 33 | 12 | 11 | 10 | 47 |
9 | Metz | 33 | 11 | 10 | 12 | 43 |
10 | Nice | 33 | 12 | 7 | 14 | 43 |
11 | Reims | 33 | 9 | 14 | 10 | 41 |
12 | Angers | 33 | 11 | 8 | 14 | 41 |
13 | Saint-Étienne | 33 | 10 | 9 | 14 | 39 |
14 | Strasbourg | 33 | 10 | 7 | 16 | 37 |
15 | Brest | 33 | 10 | 7 | 16 | 37 |
16 | Bordeaux | 33 | 10 | 6 | 17 | 36 |
17 | Lorient | 33 | 8 | 8 | 17 | 32 |
18 | Nîmes | 33 | 8 | 7 | 18 | 31 |
19 | Nantes | 33 | 5 | 13 | 15 | 28 |
20 | Dijon | 33 | 3 | 9 | 21 | 18 |
To determine a player’s attacking performance, I looked at a players’s goals and assists compared with their expected number of goals and assists. I calculated the difference between a player’s goals and expected goals (xG) and the difference between assists and expected assists (xA).
xG is the likelihood a shot will become a goal based on where the player is when they take a shot, where the keeper is, the percentage of shots from the same location and situation that have scored in the past, and other factors. All shots have an xG between 0 and 1, and this dataset’s xG number is the sum of a player’s xG over the 33 games.
xA is the likelihood a pass will be an assist, based on the location of the receiving player, they type of pass, location of other players, and other factors. All passes have an xA between 0 and 1, and this dataset’s xA number is the sum of a player’s xA over the 33 games.
A final measure I use is xG Buildup, which is essentially the likelihood a goal will come from a period of possession the player is involved in but does not deliver a final pass or take a shot. It does not include xG or xA at all. I use xG Buildup to show how different players can be, even if they have similar goal and assist performances.
To calculate a player’s goal (assist) performance, I subtract xG (xA) from their total number of goals (assists). A player is over performing when this number is positive and underperforming when this number is negative.
Goal performance depends on the player’s ability to finish chances. Outperforming xG shows they are a very good finisher—or that they are lucky. Underperforming xG means a player has squandered chances. Assist performance, on the other hand, depends on the teammate the player is passing to. Outperforming xA means that their passes are being put in the back of the net more than expected. Underperforming xA isn’t something a player can control—it means teammates are squandering chances given to them by the player, or are not taking a shot when they should.
Below is a graph showing a player’s goal performance on the x-axis and their assist performance on the y-axis. The size of each dot is their xG Buildup number. Players who have played fewer than 500 minutes are filtered out.

Follow this link to play around with the visual in Tableau yourself.
Some quick statistics about our data, the average number of xG is 2.21 and the average number of goals is 2.20. The average xA is 1.49 and average assists are 1.42. The differences between expected and actual are minimal, but we can see that players tend to have higher goal and xG numbers than assists and xA numbers.
Right away, the graph shows us that relatively few players underperform xG while over performing xA. Steve Mounié of Brest is an example. He has scored 7 goals with an xG of 10.06, but has 4 assists with an xA of 2.33.
On the other side of the spectrum, there are several players who outperform xG while underperforming xA. Franck Honorat, also of Brest, is an example here. What’s interesting is that he has recorded 8 goals and 4 assists—almost the same numbers as Mounié. Initially, I thought Honorat was passing to Mounié who turned difficult shots into goals, but only one of Mounié’s goals were assisted by Honorat.
In the top right of the graph, we can see several players who outperform both xG and xA. Kevin Volland (Monaco) and Jonathan Bamba (Lille) outperform in both metrics but perform better in one metric. Gaëtan Laborde (Montpellier) and Martin Terrier (Rennes) are outperforming both xG and xA at similar rates. Other standout players are Kylian Mbappe (PSG) and Aleksandr Golovin (Monaco).
Again, on the other end of the spectrum are players that underperform both xG and xA. Neymar is a somewhat interesting inclusion here, but with such a troubled season with injuries and bans, it is unsurprising. Lyon has 3 players that stand out in this quadrant: Houssem Aouar, Moussa Dembélé (who is now on loan at Atlético Madrid), and Karl Toko Ekambi. With Lyon 3 points behind Lille in the league, it’s tempting to think what might have been if these players were finishing their chances—and their teammates were finishing them too.
The last component of this graph is xG Buildup. We can see a vast range of values (sizes of bubbles), and there is no correlation between xG Buildup and goal performance or assist performance (correlations are 0.075 and -0.040 respectively). I included this so we can see how some players who perform similarly play differently.
A great example of players who have performed similarly this season are Neymar and Karl Toko Ekambi. Their goal and assist performances are almost the same, and Neymar’s xG Buildup is 7.38 while Ekambi’s is 6.16. They are both similarly involved in their team’s buildup play.
Kevin Volland and Kylian Mbappe are examples of players with similar performance numbers but drastically different involvements in their team’s buildup. While both players are great finishers and their teammates have done well with their chances, Volland has not been involved in the buildup as much as Mbappe, with an xG Buildup of 3.19 compared to Mbappe’s 10.09. However, these players play different styles of football, with Mbappe playing more as a winger and Volland as a striker and occasionally an attacking midfielder. But it illustrates how players with different roles and play styles can, from a goal production perspective, perform similarly.
A final player on this graph I’d like to point out is Léo Dubois of Lyon. His xG Buildup is 13.47, a whopping 1.6 above the next highest player, Aurélien Tchouaméni of Monaco. Dubois is Lyon’s right-back, not even a midfielder like Tchouaméni. You would expect midfielders to be the most heavily involved players in the buildup. However, this showcases Lyon’s tendency to move the ball up via the wings. Maxwell Cornet, Lyon’s left-back, records the team’s second-highest xG Buildup.
This graph is a good way to see which players are performing better than expected—or players who are simply lucky. Players like Mbappe, Volland, and Bamba are having exceptional seasons, whereas players like Neymar, Ekambi, and Nante’s Randal Kolo Muani are having seasons to forget. It will be interesting to see how Ligue 1 finishes since the top teams have some players who are outperforming expectations and some who are falling short of the mark. Players like Depay and Honorat have been unlucky in that their teammates aren’t turning quality passes into goals, whereas Steve Mounié has been lucky his passes have turned into goals and needs to work on his own finishing.
[…] article is an expansion of the Ligue 1 Contribution Performance article. It analyzes goal and assist performance, compared to expected goals and assists, of the “Top […]
LikeLike