The Last Day of the 2019 Allsvenskan Title Race

This post was initially intended to be a short little thing about using in-play odds to show how the 2019 Allsvenskan title race dramatically climaxed on the last day of the season, but with the current Corona situation delaying and drastically changing the new upcoming season, the synopsis grew and eventually came to focus more on my own path leading up to that glorious afternoon in Norrköping.

If you only want the short version or look at the graphs you can scroll down. And if you want a more technical explanation on the calculations behind the graphs it’s available at the bottom of this post.

Background: 1988-2018

Supporting a football club can sometimes be hard to justify. When things, as they often do, go wrong and you’ve spent a lot of time, energy and money to support your team and all you get is disappointment, embarrassment and ridicule, you sometimes start to question your decisions. Through the years I’ve done just that more times than I can remember, often on the way back home from yet another away defeat. I’ve always come to the same conclusion: that it’s really not much of a decision as the club is such an integral part of who I am. Together with my family it’s been the only constant in my life, it’s how I engage with most of my friends and it has actually brought a lot of joy with all the pain. So you pick yourself up one more time, allow yourself to start dreaming again, thinking about that one day that is sure to come if you just keep on carrying on…

Djurgården came into my life at an early stage. My father supported the club, and so naturally I had to as well. In the early and mid 90’s when I grew up Ice Hockey was the main sport in Sweden, and while my dad’s interest had long since declined to a level of watching a match on TV now and then to be able to keep up with the banter at work, my own interest skyrocketed throughout the decade. Dad’s low interest meant we didn’t go to many matches so I was instead stuck to the radio whenever Djurgården played, usually a couple of nights a week during the Ice Hockey season. The coverage was limited so you never got to hear a full match, instead you’d have to patiently wait for something interesting to happen in your match and then the radio operator would switch to the commentator on scene. I think most Swedes interested in sports back then still remember the famous goal jingle played by the Swedish Public Service radio whenever they’d switch matches to report on a new goal. Suddenly hearing it you always froze, hoping it was Djurgården who’d scored. 

Matches on TV were rare then, at least in our house as we only had the three standard channels (yes kids, that’s right) – so actually going to see the team play live was an unreal experience. I still have the flag my dad bought me on one of those days, back in November 1995 when Djurgården mounted a third period comeback to beat Modo 6-3 after being down 0-2 and 1-3. A priceless memory for a 7 year old boy.

Djurgården won back-to-back ice hockey trophies during the 1999/2000 and 2000/2001 seasons – with the latter a sweet revenge on Färjestad for the 1998 Final defeat in overtime of the deciding match – but since the 1998 World Cup, football had taken over as my main focus. Djurgården were pretty much shit then but promoted back to Allsvenskan for the 2001 season things were starting to fall into place. After an impressing second place that year, a ‘golden generation’ lead by Kim Källström, Andreas Isaksson, Johan Elmander and many more, came to dominate Swedish football with league titles in 2002, 2003 and 2005 and cup titles in 2002, 2004 and 2005 – and I was of course hooked for life.

My dad had taken me to my first football matches but by 2005 I had started going more regularly with friends. Having seen the club line up title after title (including the 2005 double) on TV I was of course very anxious to experience the ‘real deal’ myself, to climb down the stands and run onto the pitch in celebration of yet another triumph. Little did I know how long I would have to wait and the amount of suffering I would have to endure.

After those double titles in 2005 things rapidly fell apart. The following 13 years consisted mostly of pain, embarrassment and constant worries. Losing 6-0 away to IFK Göteborg, 5-1 away to Kalmar FF, and 5-1 away to Åtvidaberg brings up many ‘fond’ memories of long, quiet trips back home. So too does the horrid 2009 season when the threat of relegation hung low over the club. Nearing the end of a disastrous season, three wins were needed from the last three matches – and that only to reach the relegation play-off spot. Getting there, only to lose 2-0 away to Assyriska in the first leg, a miraculous 116th minute 3-0 winner from Mattias Jonson finally shut the relegation trapdoor without us going down through it. The last couple of minutes and the ensuing pitch invasion are some of my best memories looking back, nearly beating the trophies that would come much later on. There’s something special about a comeback like that, snatching victory from the jaws of defeat at the very last moment after having been ruled out for an entire season.

Crowd troubles were common for a couple of seasons when everything looked as darkest. Pitch invasions and abandoned matches, assaulted referees and opposition players, threats (real and perceived) against players and club officials, riots against the police and violence amongst supporters were a constant threat, it seemed all hell could break loose at any given moment. It all culminated very sadly on March 30th 2014 when a supporter lost his life just minutes before the away match against Helsingborg kicked off. Me and my friends stayed in the stands for well over an hour after the match had been abandoned, with riots on the streets outside the stadium. I will never forget the feeling of meaninglessness and emptiness. After a sleepless night train back to Stockholm I tied my scarf to the fence of the 1912 Olympic Stadium where a memorial site had been organized.

The club’s finances were for a period a constant worry and at one point bankruptcy looked likely until Daniel Amartey could be sold to Copenhagen. From then on results were slowly getting better but soon a new source of pain emerged: failing to win any of the most important matches – the Stockholm derbies – for a long time of course drew massive amounts of ridicule from our rivals. It didn’t seem to matter how much things looked to be in our favor before kickoff, or how many goals we were up – we just couldn’t win.

But all this only strengthened me and my friends. Having traveled up and down the country during the darkest years we were starting to dream of new victories again, although quietly so at first. Amidst the chaotic first part of the 2013 season, with the manager and chairman having just abandoned ship after a series of losses and some ’hard words’ from supporters, we had suddenly been given a surprise chance. Playing IFK Göteborg in the cup final we again had our eyes on a title, but eventually losing in a penalty shootout we would have to wait 5 more years until we got another chance. By then the club had been almost transformed.

With Bosse Andersson and Henrik Berggren back in the club, finances were slowly improving year after year, and with Kim Källström and Andreas Isaksson back in the lineup, a third place was secured in 2017. With it came a much awaited chance to travel abroad for the next season. Having spent 10 years regretting not going to Tallinn and Trondheim in 2008 I wouldn’t make the same mistake of waiting out ’better’ trips again. The 2018 European campaign began and ended in Odessa after a dodgy penalty for 2-1 in extra time and a 3-2 loss on aggregate, but the whole trip felt like a huge bonus after finally winning a trophy a couple of months earlier.

The 2018 cup win felt like a massive payoff after more than a decade of blood, sweat and tears and after sweeping Malmö 3-0 at home (and AIK 2-0 away in the semi, at last!) I was on a high for weeks and months. But despite finally standing triumphant the ultimate prize still haunted me. Winning the short and unpredictable cup was one thing, going the distance and competing over 30 rounds for the league title was something completely different.

The 2019 Season

Going into the 2019 season I didn’t expect much. New coaches Thomas Lagerlöf and Kim Bergstrand were known for their systematic approach at Sirius, but also for their long playing careers at AIK so they would have to work hard to convince me and many others. You could immediately see they’d done wonders to the team’s organization and discipline on the pitch though, and if it wasn’t for an extra time defeat to Häcken in the semi final, I’m sure they’d steer the team to repeat the cup triumph from the year before, with AFC Eskilstuna waiting in the final.

The team seemed to struggle due to injuries and sickness during the first part of the season but still managed to top the table after refusing to lose, most notably winning 1-0 away to Häcken where we had lost 5-0 the year before. The losses finally came against Hammarby and AIK and what had looked like a promising start now felt just like any season again. But the players stepped up and with the injury situation improving we were back at the top well after the half-season mark, only briefly surpassed by arch rivals AIK for two rounds. The table was starting to settle now, and it was getting clear that the four big clubs Djurgården, Malmö, Hammarby and AIK would battle it out for the title.

When it was time to face Malmö away we were three points clear and had a great chance to make ourselves strong favorites for the title just by avoiding a loss. I had run my simulations to investigate different scenarios and it was clear that this match was something of a crossroad. If we lost we would lose momentum and have a hard time to defend the lead, but a win or a draw would be a big step on the way. Unfortunately I couldn’t join my friends for the trip and had to watch the match at home, something I absolutely hate as I get so much more nervous when I can’t be in the stadium. Looking back this was definitely my most nervous day prior to the last one as I knew how crucial the match was. It’s the toughest away match in Sweden but the players stood up well and when Mohamed Buya Turay scored on a beautiful counter attack and Tommy Vaiho saved a penalty just minutes later, I nearly had a heart attack. We won that match and I was now starting to believe we could make it. Unfortunately we lost to both AIK and Hammarby after that but the Malmö win had given us room for errors and with just one match to go we were still on top of the table.

The title race up until the last match had been extreme. With one round still to be played there were now three teams above 60 points for only the third time ever, and it looked likely there’d be four teams above that threshold for the very first time when all was said and done. Usually you’d win by taking 60-62 points but now you would have to take home much more than that to lift the trophy. AIK had dropped out of the title race in the 29th round but the four biggest clubs in Sweden had really pushed each other to extremes this season, and it would all be decided in the very last round.

last

The conditions were clear going into the last round: Djurgården were on top and could afford to draw away to Norrköping as Malmö and Hammarby were three points behind. Having to look to Norrköping for help, Malmö played away to a Örebro with nothing to play for while Hammarby at home faced Häcken, also with nothing to play for. They both needed to win to take the title by goal difference, with Malmö having the upper hand there with +35 against Hammarby’s +34. If equal on goal difference Hammarby would take it all thanks to their superior goal record.

As indicated by betting odds and my own simulations, title chances looked close to 70%, 20% and 10% for Djurgården, Malmö and Hammarby respecively.

Match Day

Waking up much too early I spent the morning battling nervousness and when it was finally time to leave I apparently just grabbed a bottle of whiskey and mumbled some strange kind of goodbye to my very understanding girlfriend. The nervousness had to be countered with Irish Coffee’s for breakfast in the backseat of the car and some pre-kickoff beers once arrived, despite my intention of keeping the drinking to a minimum so I could stay sharp. It was just enough to calm my nerves and I was starting to feel very optimistic about the day, with a strange kind of euphoria kicking in.

Kickoff

0080

By the time the referee blew the whistle I had made the mistake of trying to find a working toilet with just 30 minutes till kickoff. Naturally the away stand was jam-packed when I came back and I had no way of getting through to my friends. Walking round the stand to find some space in between it and the pitch, I just managed to take up position to the right of Norrköping’s goal before the ball was in play. According to the odds we had about a 70% chance for the title and I’d made the calculations myself the night before but my optimism now made it feel like 90% and I was anxious to get on with it.

8’ – 1-0

0555

Just a couple of minutes in Norrköping got a corner at the far end of the pitch and after some minor crowd disturbance delaying it, the ball ended up in the net behind Tommi Vaiho. The away stand fell silent for a moment while the home fans exploded in taunting celebration. But singing soon picked up again and I was still confident we could make it, after all we only needed one goal and there was plenty of football left. Our chances had just dropped to about 40% but still optimistic, it felt more like 75% to me.

15’ – 2-0

0942

If the first goal was a slap in the face, the second was a kick in the teeth. Just 7 minutes later we were suddenly 2-0 down and had a mountain to climb to take home the title. Optimistic as ever though, I had no room for negative thoughts. It was still early, we’d started to take control of the match despite conceding again, and eventually the will to win surely must weigh over in our favor as Norrköping’s only motivation was to ruin our day. I didn’t know it but we were down to about 20% now. My optimistic psychosis didn’t loosen its grip though and to me it was now a 50/50 shot.

Half time

3028

When half time came I climbed up to the top of the stand to find my friends. Not much was said but I could feel they weren’t as positive as I was. But it was still just two goals so I tried to spread some hope. Thankfully, no one had given up yet.

50’ – 2-1

4303

When play resumed Djurgården continued to dominate, applying that slow, patient and grinding control that had resulted in so many late winners during the season. In the 50th minute it finally paid off when Jesper Karlström met a cleared corner with his right foot, guiding the ball into the back of the net. The stadium exploded with Djurgården supporters everywhere but the home stand. We were back to about a 40% chance for the title now but it felt like we were all the way back to where we had started at 70%. Surely, the goal would come?

65’ – 2-2

5205

Djurgården had been piling on the pressure since the goal and 10 minutes later Emir Kujovic got the ball on the left side of the box and whipped in a hurried half shot, half cross. The ball didn’t need to travel far from Mohamed Buya Turay’s foot for me to see what was going to happen. Standing high up in the away stand I was in a perfect line with Turay and the keeper, and suddenly reality kicked in. My optimistic psychosis was completely gone and not even seeing the goal, I immediately sat down and started crying tears of joy, and of relief. Soon my close friend, always on the lookout for jinxes to clamp down on, pulled me up and scolded me before giving me a hug: “Not yet you idiot, there’s still much left!”. In reality we’d jumped up to nearly a 80% chance but my mindset had reversed a full 180 degrees and I now felt we were back at a 50/50 shot, at best.

75’ – Tick, tock…

5771

Time was moving extremely slowly now and I was starting to get way too nervous. A 73rd minute red card for Norrköping did help to calm me down but despite time actually working for us now I was still pessimistically feeling a 50/50 shot. Back in the real world, we were approaching 90%.

90’ – So close

6671

Stoppage time was announced and seeing the number 5 come up didn’t help to calm my nerves. Elliot Käck’s 93rd minute tackle giving Norrköping one last real chance with a free kick out on the wing nearly gave me a heart attack but the players managed to keep the home team at bay while my friend loudly cursed anyone who dared celebrate too early.

96’ – The Final Whistle

7037

At 95:06 the referee finally blew the whistle and the pitch invasion started in wild celebration. We remained in the stand for a minute, hugging everyone we could find, before slowly climbing down and onto the pitch. It was a surreal feeling, like it all happened in slow motion, with people and manic euphoria all around us. In the centre circle we met more friends, some of them having travelled to Norrköping without any tickets yet somehow managing to enter the stadium through the away stand just as the final whistle blew. We stood there hugging, singing and celebrating as the players came out and the trophy was finally lifted. After 14 years of waiting and nearly 10 years of agony since the dramatic play-off match in 2009, we’d made it.

Epilogue

It took me a while to realise what had actually happened. I had dreamed of it my entire life but it still felt so unreal. It was only a couple of weeks after the match it finally set in that we had won and I could start to enjoy it for real. 

GIF2019

With the Corona virus delaying the start of the 2020 season and Allsvenskan kicking off without any crowds tomorrow I am ever more thankful for the win, as it would without a doubt feel even more strange without it. I don’t know how long it will take until me and my friends can discuss players, transfers, managers, referees and everything else over a couple of beers before seeing Djurgården play again, but I do know that fulfilling a lifelong dream last November certainly will make the wait so much easier.

A brief technical explanation

Historic in-play odds are hard to find but signing up for a free trial at Statistic Sports I found something I could work with. Using 3-way next goal odds I was able to derive goal expectancies (using a method I will keep undisclosed) for each team in the three relevant matches. There were only updated odds available about every minute or so and I wanted to calculate percentages for every second so I just had to assume that odds remained unchanged between updates. In reality this isn’t the case as odds can change many times per minute but it was good enough for me. Using the goal expectancies and the manually inputted goals scored I used a very simple Poisson approach to populate a correct score matrix for each second of each match.

Now, instead of having to simulate all three matches every second to get a set of final tables and win percentages, I instead calculated which unique combination of results would end up in a league title for Djurgården, Malmö and Hammarby respectively. With a correct score matrix of 0 to 10 goals this meant 121 possible results per match, and 1,771,561 unique combinations in total. This took way too long for my liking so after studying the table as it looked at the start of the last day I instead chose to work with goal differences as individual goals didn’t matter, only goal differences. With the same 0 to 10 matrix this left me with 11 goal differences per match and 1,331 in total, a much smaller number.

Having all possible goal difference combinations linked to their respective title winner I could now easily calculate win percentages for each second. Keeping everything on the same scale I started off at the official kick off time 13:00:00 and went from there, manually fitting it with the (real and game) time stamped odds to come up with the underlying data for the graph.

Advertisement
The Last Day of the 2019 Allsvenskan Title Race

Scale matters – how to not track your betting results

This blog post is one of the half-done follow-ups to the staking post I did back in 2017. I wrote most of it at the same time as the original post but busy with work and other projects I never got to finishing it until now. What prompted me to finally publish was an interesting discussion on Twitter on how to best track your bets. The discussion fit well with what I had intended to say with the post so here you go, my first (and last) blog post of 2019.

Ok, so we start out with the same situation as last time: a punter has set out to bet on 10,000 coin flips. The big difference here is that he doesn’t know if the coin is fair or not, i.e. if he has an edge or not. He can choose to quit at any time though, so if he suspect he’s getting the worst of it he can just call it quits and save his time (and money). Speaking of time, manually flipping 10,000 coins is some task and as our punter has other things to do on most days, he’ll limit his betting to 10 flips a day. This will make the total series of 10,000 flips take 1,000 days, or roughly 2.7 years.

And now to the main point of this exercise. The result of each coin flip is recorded by a trustworthy third party and made available to all parties only when time for settlement. The bets should be settled on a regular basis but exactly how often is up to the punter: every day, week, month or year?

Now remember that our punter doesn’t know what his edge is, or even if he has one. What time frame should he choose to settle his bets on? In the real world, there’s probably no correct answer as this is mostly down to individual factors like total net worth, appetite for risk, tolerance of variance etc etc.

But, we can try to gain some insights by simulation. Using the coin flipping code from last time (ignoring the bankruptcy part) and adding on a function to compare the different settlement intervals we can run a simulation of the punter’s 10,000 coin flips to see how the results would look if he were to settle the score by each day, week, month or year.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set()

def coin_flips(n=10000,odds=1.97,bankroll=100,stake=1,bankrupt=False):
    '''
    Simulates 10000 coinflips for a single punter, betting at 1.97 odds,
    also calculates net winnings
    
    NEW: default bankroll and stake set at 100 and 1, respectively
    now also calculates if player went bankrupt or not
    '''
      
    # create a pandas dataframe for storing coin flip results 
    # and calculate net winnings
    df = pd.DataFrame()
    # insert n number of coinflips, 0=loss, 1=win
    df['result'] = np.random.randint(2,size=n)
    # calculate net winnings
    df['net'] = np.where(df['result']==1,stake*odds-stake,-stake)
    # calculate cumulative net winnings
    df['cum_net'] = df['net'].cumsum()
    
    # calculate total bankroll
    df['bankroll'] = df['cum_net'] + bankroll

    # if bankroll goes below the default stake, punter will stop betting
    # count times bankroll < stake
    df['bankrupt'] = np.where(df['bankroll']<stake,1,0)
    # count cumulative bankruptcies, with column shifted one step down
    df['bankruptcies'] = df['bankrupt'].cumsum().shift(1)
    # in case first flip is a loss, bankruptcies will be NaN, replace with 0
    df.fillna(0,inplace=True)
    # drop all flips after first bankruptcy
    if bankrupt:
        df = df[df['bankruptcies']==0]
    
    return df

def compare_scales(n=10000,odds=2.03,n_day=10,df=False):
    '''
    Puts coinflips on a timeline to
    10/flips per day, 30 days/month
    '''
    
    # if no df specified, create a new one
    if not df:
        # create df of a single punter's coinflips
        df = coin_flips(n,odds)
        
    # calc number of days
    days = n / n_day
    # ...weeks
    weeks = n / (n_day*7)
    # ...months
    months = n / (n_day*30)
    # and years needed
    years = n / (n_day*365)
    
    # insert days
    df['days'] = np.repeat(np.arange(1,days+1),n_day)
    # ...weeks
    df['weeks'] = np.repeat(np.arange(1,weeks+2),n_day*7)[:n]
    # and months
    df['months'] = np.repeat(np.arange(1,months+2),n_day*30)[:n]
    # and years
    df['years'] = np.repeat(np.arange(1,years+2),n_day*365)[:n]
    
    # list of scales
    scales = ['days','weeks','months','years']
    
    # figure, subplots
    f, axes = plt.subplots(2,len(scales),gridspec_kw={'height_ratios':[len(scales),1]},
                           sharey='row', figsize=(12,6))
    # reorder axes
    day_axes = [axes[0][0],axes[1][0]]
    week_axes = [axes[0][1],axes[1][1]]
    month_axes = [axes[0][2],axes[1][2]]
    year_axes = [axes[0][3],axes[1][3]]

    axes = [day_axes, week_axes, month_axes, year_axes]
    
    # loop through views, groupby and calc cum net,
    # plot cum net and 'view' net
    for s, ax in zip(scales,axes):
        # groupby, recalc cumnet
        group = df.groupby(s).sum()
        group['cum_net'] = group['net'].cumsum()
        
        # plot total cumulative net as line
        group['cum_net'].plot(ax=ax[0])
        # and daily/weekly/monthly net as bar
        group['net'].plot(ax=ax[1],kind='bar',linewidth=0)
        
        # clean up lower plot x axis
        ax[1].set_xlabel('')
        ax[1].set_xticklabels('')
        ax[1].grid(False)

        # insert horizontal line at breakeven on both plots,
        # add label
        for i in ax:
            i.axhline(color='k',alpha=0.5)
            i.set_ylabel('Net profit')


    # fix the yearly y-tick labels to show whole years only
    ax[0].set_xticklabels(['1','','2','','3'])

    # 'fix' layout
    plt.tight_layout()
    # show plot
    plt.show()

Running the compare_scales() function returns a graph of the simulation results. With the default 2.03 odds (an 1.5% edge on a fair coin) it could look like this (though this particular results graph was chosen to prove my point):

02

So the above graph is the results of the same 10,000 coin flips settled on different time frames, or scales. We can see that our punter ended up a clear winner, making a stable profit every year. But what if he’d been settling his bets by the end of every day? Would he, not sure whether he really had an edge, resist the urge to quit and do something else with his time (and money) after being roughly breakeven sometime after 100 days? We can never know of course, but by settling the bets every day our punter exposed himself to a lot of randomness, opening up for a very bumpy mental ride as he had to face many losing days. We know he had an edge, but he didn’t, and having to pay up again and again he might just had called it quits then and there. The same goes for the huge downswing leading up to 400 days. Would he have weathered the storm?

My point here is that if he’d chosen a longer time frame to settle on, he wouldn’t even know about his losing days. Settling by the end of each week would see him exposed to a lot more winning than losing settlements, and even more so if he’d chosen months or years. This would of course increase the likeliness of our punter staying in the game to eventually profit from his edge. On the other hand, it could have prevented him from realizing he was losing badly, having to face a very expensive settlement he could have avoided by settling more often.

Keeping track of your results is of course crucial to betting success as you want to know how, when, where and why you win or lose to be able to improve your underlying process, but if you expose yourself to too much randomness you risk clouding your judgment and make changes to what could be a profitable betting process, or maybe even quit – not realizing you actually had an edge.

I’m not saying you shouldn’t track your bets at all, and I’m not saying you should only look at your betting results once a year – what I am saying is that you should try to avoid making decisions based on randomness. It’s an easy mistake to make and I see it all the time on Twitter, from people touting their daily betting ROI to discussions about the Expected Goals score of an individual football match. It’s human nature, but you should still try to avoid falling into the trap.

Even if you have an edge, the results of any football match or betting day, week or month will likely be due to a lot of randomness and are most often irrelevant. What matters are the decisions behind the results.

Scale matters – how to not track your betting results

Allsvenskan 2018 Summer update 2

Last time, I took a look at how the teams in Allsvenskan have performed this first part of the 2018 season leading up to the World Cup break. As I promised then, I will now look closer at individual player performances. Before we begin though, it is important to underline that Stratagem’s data is a bit different than other sources, so please read the beginning of this post to be able to better understand the stuff I’m about to show.

Note: In some of the scatter plots below I’ve excluded what I deem to be outliers due to the small sample size.

Goalscoring

01.png

Scoring 4 goals against Sirius in the last match before the break, Djurgården’s Tino Kadewere tops the league in non-penalty goals at 8, overperforming his second place xG of 5.5. He has also gotten into most chances so far, showing some great form.

Another strong performance comes from Hammarby’s Pa Dibba, the speedy forward being one of the main reasons behind their attacking success. He leads the league in xG at almost 6 to go with his 7 non-penalty goals, but what really makes him stand out is his time-weighted performance, dominating with over 1 goal and 0.92 xG per 90 minutes played.

Nikola Đurđić has been the other focal point in Hammarby’s attack and the Serbian has been just what Hammarby needed. Besides goals, he has also brought grit and a mentality which has maybe been missing in Hammarby.

Romain Gall has impressed with 5 goals for Sundsvall, and will likely be on the radar of the bigger clubs for the upcoming transfer window. Interestingly, IFK Göteborg’s Giorgi Kharaishvili leads the league in Chances per 90 minutes.

02.png

Plotting goals and xG we see just how good Dibba has been so far, and also that compared to last season, a lot of players are running really hot and overperforming their xG numbers. There’s a sample size problem here of course, as we’ve only seen 10-12 matches per team but it will be interesting to see if it continues the same way after the summer break.

03.png

Looking at Player Attacking Styles we see how Dibba has been combining a lot of chances with a high average quality. Moberg-Karlsson, Paulinho and Kharaishvili have similiar chances per 90, but of considerably lower quality and hence have scored less goals. Inversely, Alhassan Kamara, Dino Islamovic, Carlos Strandberg and Đurđić have ended up in chances of roughly equal quality as Dibba, but less often, again having scored less goals. From the previous plot we see that Kamara and Strandberg also have efficiency problems compared to their xG but if they can keep their high average chance quality they should get the goalscoring running again soon, as they’re both usually very strong in front of goal.

Chance Creation

04.png

The creators behind the chances then? Well, Örebro’s Nahir Besara is as usual up there when it comes to assists, as is Ken Sema of Östersund. Hammarby’s Jiloan Hamad has had a strong season so far as well, being one of the main driving forces behind Hammarby’s attack. Tino Kadewere shows his versatility by producing 5 assists to add to his goals, though it is worth mentioning that two of these are rebounded shots. Another attacker showing some creativity is Đurđić who’ve created over 3 xA so far.

Adjusted for minutes played we see that old boy Tobias Hysén is still important to IFK Göteborg’s chance creation, and that Östersund’s Hosam Aiesh has created most xA per 90 at about 0.5. The small sample size sees Brommapojkarna’s Marko Nikolic make the list with his 2 assists from 340 minutes played.

Häcken’s Daleho Irandust is one of the most frequent creators, leading the league in Chances Created per 90, ahead of Arnor Traustason and Alexander Jakobsen of Malmö and Norrköping, respectively.

05.png

Plotting actual and expected assists, we again see a lot of overperformance which is of course linked to what we saw with the goals earlier. Malmö’s Markus Rosenberg has been one of the most notorious under-performers against xG in my models for years, but here he interestingly shows up underperforming xA instead. This of course has a lot to do with the sample size, but also indicating that he has switched role in Malmö’s attack a bit, and that his teammates haven’t been that clinical when he’s set them up with chances.

06.png

Looking at how the players create chances, we see how some like Irandust, Jakobsen and Traustason focus on volume, while Đurđić, Kalmar’s Måns Söderqvist and Nahir Bahoui of AIK create chances less often, but of a higher quality. As with goals, the strongest producers like Besara, Hamad, Kadewere and Sema manage to combine both aspects when setting up their teammates. AIK’s Rasmus Lindkvist and IFK Göteborg’s Emil Salomonsson are the only defenders showing up here, both operating as wing backs in front of a 3-back line.

Attacking Production

07.png

Tino Kadewere dominates when it comes to raw numbers, leading the league in G+A, xG+A and Chance Production, but drops a bit when taking playing time into consideration as Djurgården’s lack of options up front has seen him play a lot of minutes.

Dibba and Đurđić again show up as strong producers, and Sundsvall’s Linus Hallenius also deserves a mention being third in G+A per 90 and fifth in xG+A per 90. Norrköping’s young icelander Arnór Sigurdsson has also impressed with over 0.6 xG+A per 90, as has AIK’s Anton Salétros, whose fine performance and 0.84 G+A per 90 earned him a move to Rostov in the Russian league.

08.png

Naturally we see a lot of overperformance when combining goals and assists as well, and we should expect to see some of these players’ output to normalize over the season. Who that will be is of course a lot down to chance itself.

09.png

Plotting xG and xA we can get a glimpse of the production style of players. Dibba is of course the typical striker with a lot of xG but little xA created, while Aiesh seem to be the direct opposite. A strong group of players lead by Đurđić combine both execution and creation.

The small sample size is of course a problem and could be one of the reasons we see no real one-sided ‘role players’ besides Aiesh and Dibba yet. Sema, Traustason, Irandust and others should all belong to the more creative group but have for various reasons failed to create enough xA for it to show yet. On the other side of the scale, we know that Kamara, Strandberg and Kalle Holmberg are all strong strikers heavily focused on being at the business end of chances just like Dibba, but they’ve struggled a bit so far. It will be interesting to see how things develop over the season.

Player Profiles

T. Kadewere_chanceT. Kadewere_creation

I mentioned Tino Kadewere back in 2016, at the very end of this post. Since then, he’s missed much of 2017 to injuries and when fit struggled to get back to form. One of the reason for this is him having to adopt to a new role as the sole striker up front as goalscorer after goalscorer have left Djurgården. His display has been sometimes puzzling this season as he at least early on mixed insane misses and poor touches with equally jaw-dropping dribbles and smart play. As time has progressed though he’s looked better and better, being instrumental in Djurgården’s Swedish Cup win with 4 goals in 7 matches, to add to his 8 in Allsvenskan. Previously used as more of a creative support attacker he has now evolved into a centre forward with impressive hold up play and a presence in the box, which is evident from his very good chance locations. Add his creative side and it’s no wonder he’s rumoured to be on the radar of clubs abroad.

P. Dibba_chance.png

Pa Dibba has impressed as well, and though usually applauded for his speed and counter-attacking skills adding a dimension to Hammarby’s attack, he has some very useful skills poaching in front of goals on crosses and set pieces as well, as can be seen from the 3 high-quality chances close to goal.

N. Đurđić_chanceN. Đurđić_creation

Nikola Đurđić’s return to Allsvenskan (10 goals in 11 matches for Helsingborg in 2012 and 5 in 12 for Malmö in 2015) is another reason for Hammarby’s success so far. Overperforming his xG a bit, he has still gotten into some very good chances and brings a lot of overall quality as well, creating high quality chances for his teammates. As mentioned he has also brought in a kind of grit and mentality that I think has been missing in Hammarby for quite some time.

R. Gall_chance

Sundsvall’s Romain Gall has been one of the most in-form players so far and could be on his way to a bigger club soon. As can be seen from the above plot though, his 5 goals is a bit flattering compared to his xG, but if he can get the right coaching and learn to be a bit more selective when it comes to chance locations, I think he could grow into a very strong winger.

N. Besara_chanceN. Besara_creation

Just like last season, Nahir Besara has been the driving force behind Örebro’s attack. Possibly limited a bit by Axel Kjäll’s more cautious approach, he has still had an impressive spring. Combining some good quality chances inside the box with efficient long-range shoot and strong passing foot, it’s tempting to think about what he could do at a bigger club.

D. Irandust_creation

Daleho Irandust is Allsvenskan’s most frequent creator, third in raw quantity and leading the league in chances created per 90, but what good does that do when his teammates simply refuse to score? Not super high average chance quality though but given time and his undeniable talent, assist will come.

J. Hamad_chanceJ. Hamad_creation

Jiloan Hamad is the main creator in Hammarby’s midfield, being the driving force behind much of their attack. He can score as well and his strong season so far saw him involved in the discussions for Sweden’s World Cup squad, though he was eventually left out.

K. Sema_creation

Another strong creator who was in contention for the Swedish squad is Ken Sema. Though not yet as impressive as last season, he has been creating chances for Östersund  this spring and his strong performance in the Europa League could very well earn him a move abroad soon as quite a few players could be leaving the club after Graham Potter’s departure.

C. Strandberg_chance

Arguably one of the best strikers in the league, Carlos Strandberg has, just like all of Malmö, struggled so far. Still getting into great chances and scoring goals, he is lacking a bit in volume though and will need to get up to speed and improve a lot if Malmö are to climb the table after the summer break. He has a great left foot and should shoot more, in my opinion.

R. Lindkvist_creation

Left wing-back Rasmus Lindkvist has been a big part of AIK’s attack with his 4 assists and 12 chances created so far. Interestingly, he doesn’t use his wide position to whip in crosses, instead using his good pace and passing foot to combine his way into the box where he sets up his teammates in front of goal, which seems to work out quite well for him.

If you want to see any more Player Chance/Creation Maps, just let me know on Twitter.

This article was written with the aid of StrataData, which is property of Stratagem Technologies. StrataData powers the StrataBet Sports Trading Platform, in addition to StrataBet Premium Recommendations.

Allsvenskan 2018 Summer update 2

Allsvenskan 2018 Summer update

Allsvenskan is on a break waiting for the World Cup, and so am I – so why not write a quick recap of the action so far? Well I hadn’t planned on it, but with this first part of the season being far more interesting than what we’ve seen in a long time, I simply couldn’t resist.

01

The number of matches played are a bit unevenly distributed so far, with Malmö, AIK and Djurgården all having played one extra match each to give room for the European qualifiers later this summer, while Sirius‘ season opener against Sundsvall was postponed due to poor pitch conditions.

The main (and I mean MAIN) narratives so far have been Malmö’s fall from grace and Hammarby‘s surprisingly flying start to the season. A mini narrative this season is also Östersund with their poor start, criminal investigations into chairman Kindberg‘s business and manager of the year for the last two seasons, Graham Potter, leaving to take over Swansea in the Championship.

Title defenders Malmö very disappointingly sit in 10th and are nowhere near their usual standard which has seen them claim the top spot 4 times in the last 5 seasons. Magnus Pehrsson was under a lot of pressure early on and after failing to bounce back after the 3-0 defeat to Djurgården in the Swedish Cup final, he was soon fired.

Hammarby on the other hand got off to a great start, winning 8 and drawing once before finishing with their first defeat of the season (against rivals AIK) and another draw. For a team that finished 9th last season, looked quite poor, sacked their manager and promoted his assistant in a move that looked like a huge gamble, this is surprising even for Allsvenskan. Fair play to Hammarby and Stefan Billborn though, they have undeniably been the best team so far, playing a very entertaining attacking football.

That said, let’s get on with some scatterplots:

02

Looking at chances we can see that Hammarby spend a lot of time attacking, while at the same time limiting their opponents. Häcken does a good job as well, and Malmö actually don’t look too bad quantity-wise. AIK is a curious case with Rikard Norling as usual having his side focus more on game control than chance dominance, limiting their attack even more than last season. A bottom quartet of Dalkurd, Trelleborg, Sirius and Brommapojkarna can be easily distinguished here, with especially promoted BP looking really poor when it comes to raw chance numbers, facing a whopping 17 chances per match.

03

Hammarby have been effective in front of goal, which when combined with their many chances of course is a big part of their impressive run so far. Malmö and Häcken on the other hand have seen their good numbers spoiled by some ineffective finishing, while AIK’s effectiveness has compensated for their low quantity and allows them to aim for the top. Brommapojkarna’s performance is dismal here as well, and we can also note that IFK Göteborg worryingly combine low chance quantity with ineffective scoring.

04

Looking at defensive effectiveness we see how Hammarby are actually quite poor, proving the point that their success is mostly down to their impressive attack. Malmö and Östersund look surprisingly bad as well, on par with bottom teams Sirius and Dalkurd. Had they defended better they would have gone into the summer break with far more confidence of a top 3 finish, and I don’t even want to think about how Hammarby would look if they get their defense in shape.

AIK is of course the master defenders, handling the few chances faced very effectively, as is Norling’s trademark. As we’ve seen though, they’ve done so by giving up some attacking ambition, relying more on effectiveness in front of goal. There could be a fine line between success and utter failure with this approach but I suspect AIK to be in the race for the title up until November.

Bottom placed Sirius look really poor defensively and as usual they are plagued by injuries as well. They’ve also had to start with their goalkeeping coach a few matches as their only fit goalkeeper was suspended after a cocaine-related offense, which certainly didn’t make things easier. Brommapojkarna’s defensive effectiveness look OK but they still face way too many chances to avoid being involved in the relegation battle.

Lastly, Örebro have dramatically improved their defense under new manager Axel Kjäll, going from around 7.5 chances faced per goal conceded last season, to almost 12 so far. They still face a lot of chances but defend these well, looking very much to have a deliberate strategy to defend the box and let the opposition bomb away from poorer chance locations.

05.png

Looking at the Expected goals scatter we see just how different Hammarby and AIK’s approaches are. Interestingly, this fits very well with the traditional values of the clubs with AIK focusing a lot on a solid defense looking for a controlled 1-0 win while Hammarby attack head on carefree, not minding conceding a goal or two as they can always score more if needed.

Besides the top 2 teams, there seems to be some clustering going on xG-wise. A group of 5 clubs including Malmö and Djurgården look to be in contention for a top 3 spot with average or better defenses and strong attacking, while a roughly average quartet are lead by Örebro. Lastly, we see how the bottom quartet is actually a quintet with Sundsvall also showing poor underlying performances in both ends of the pitch.

06

The clustering shows up when looking at Expected Goals Difference as well, also showing that Häcken is actually on par with AIK and that Östersund is slightly worse than the other top 3 contenders. Sirius are just bad.

How about a prediction then – will the main narratives continue or will Malmö regain their form and will Hammarby drop back to their former mediocrity? Who will be relegated? Well, even if I wanted to make a prediction, we’ve seen just a bit more than one third of the season so far and there’s still a lot to come, including a very interesting transfer window which could see most clubs look very different come mid August. The only thing I can say is that the remainder of the season could very well get even more interesting than what we’ve seen so far.

That’s it for now, but I will hopefully be back soon with an update on individual player performances.

This article was written with the aid of StrataData, which is property of Stratagem Technologies. StrataData powers the StrataBet Sports Trading Platform, in addition to StrataBet Premium Recommendations.

Allsvenskan 2018 Summer update

Allsvenskan 2017 Summary Part 2

Alright, after my last post discussing team performance for the 2017 season it’s now time to dig deeper into Stratagem‘s great dataset and have a look at individual players.

As usual, it’s important to remember that Stratagem collects chances, not shots and also this: only one chance per attacking play is recorded. So for example if a team forces a goalkeeper to a series of saves in a single attack, only the highest rated chance (or a goal if it was scored) is recorded – this of course makes much sense as you can only score a maximum of one goal per attack.

Another difference from most data collectors is that whenever a blocked or saved shot rebounds and leads to a new chance, Stratagem credits the original shooter with an assist for his part in ‘creating’ this new chance. It’s important to note though that this only happens if the rebound chance happens to be of a higher quality than the original chance or end up as a goal, due to the above rule of only one chance per attack.

Lastly, when it comes to minutes played I’ve taken some time to try to calculate it as correctly as possible to get a better look at players ‘true’ performance. Sites like Soccerway seems to set their maximum playing time per match to 90 minutes which is of course wrong as there’s usually a lot of injury time to consider, sometimes even in the first half. So for this post with injury time in both halves taken into consideration you’ll see players which have played more than 30 units of 90 minutes and this also means that most players will see their per90 stats slightly diminished.

All data is open play chances, i.e. penalties are excluded for this post.

But enough of that, let’s get to it and have a look at some numbers. As usual I’ll just throw some plots at you together with my spontane thoughts:

Goalscoring

01Though sharing honors as the league top scorer at 14 with Magnus Eriksson, the moral winner is Norrköping’s Kalle Holmberg with 13 open play goals while 5 of Eriksson’s goals came from penalties. Eriksson’s 9 open play goals is still very impressive though, seeing him finish joint second together with a group of strong goalscorers, all forwards – while Eriksson has mainly been used in midfield in Özcan Melkemichel’s Djurgården.

Another impressive performance comes from AIK’s Nicolas Stefanelli who managed to reach 9 open play goals despite only arriving during the summer, resulting in him topping the league when it comes to goals scored per 90 minutes. Versatile Bjørn Paulsen‘s 8 goals are equally impressive as he’s been used in both central midfield and defence alongside his starts up front for Hammarby.

Tobias Hysén shows that he’s still to be reckoned with, producing the highest total xG in the league at age 35. I’ve been waiting for his performance to drop for some years now, will he surprise me again next season?

The lack of any real xG per 90 Wizard this season (besides Stefanelli, maybe) sees some surprising names break into the immediate top. Johan Bertilsson, Skhodran Maholli (though he enjoyed an initial strong start to his arrival at Sirius) and Linus Hallenius comes to mind. Impressive of course, but it should be noted that this Allsvenskan season has been lacking the strong goalscoring box-player poacher type like pasts seasons’ Kjartansson, Owoeri and Kujovic. Kalle Holmberg could’ve been that player but IFK Norrköping’s weak end to the season has certainly limited his output to more normal levels.

Eflsborg’s Issam Jebali was the end point of most chances for the season, but when playing time is taken into consideration, AIK’s Nicolas Stefanelli once again reigns supreme.

02Comparing goals and xG we see that Stefanelli’s output isn’t that much better than expected, he could very well be the real deal. Another interesting point is that Malmö’s captain Markus Rosenberg continues to underperform against xG.

03.pngLooking at how many chances players create and the average quality of those chances should give us at least some sense of their preferred attacking styles. We see here how most strong attacking players tend to cluster around an area of compromise between quality and quantity. In this group, Viktor Prodell, Johan Bertilsson, Henok Goitom and Mohamed Buya Turay tend to rely more on high quality chances (all above 0.20 xG per chance), while David Moberg-Karlsson and Stefanelli prefer to just rack up chance after chance, the latter with some respectable xG per chance as well.

Moses Ogbu is an extreme outlier with over 0.30 xG per chance, explained in part by the fact that he only took part in Sirius’ very strong first half of the season before getting injured. Still a very interesting player, his numbers would likely have dropped a bit had he been fit to play when Sirius struggled (including 7 straight losses) in the second half of the season.

Chance Creation

04.pngElfsborg’s Simon Lundevall provided most assist overall but taking playing time into account, IFK Norrköping’s Niclas Eliasson was Allsvenskan’s main creator this season. Racking up 11 assists in the first half of the season before leaving for Bristol City in the Championship, his departure effectively ended Norrköping’s top 3 ambitions.

Magnus Eriksson, Tobias Hysén and Nahir Besara‘s appearance in the Assists Top 10 really shows their versatility and huge importance to their teams’ overall attack.

Just like seen with goals above, some interesting and perhaps surprising names appear when we account for playing time. I certainly didn’t expected to see Sirius’ Elias Andersson or AFC Eskilstuna’s Andrew Fox here, but there you go.

Ken Sema‘s strong finish to the season saw him (besides earning a call-up to ‘Party-‘ Janne Andersson’s national team which beat Italy to advance to the World Cup) top the Expected Assists table at roughly 11, though 3 less than his actual output. Sema has also been performing well in Östersund’s Europa League campagin and is one of many players they’ll have to work hard to keep over the winter transfer window.

Nostalgic as I am, it’s certainly nice to see my boyhood hero Kim Källström racking up some strong numbers placing him in the Top 10 Assists and xA tables, as well as creating most chances in the league overall and 4th most when taking playing time into consideration.

05.pngComparing assists and xA we see how Niclas Eliasson has been outperforming his expected output (likely thanks to some effective scoring from Kalle Homberg) while Ken Sema has been underperforming. Lundevall is closer to his expected output.

06.pngJust like with the Attacking Styles, Player Chance Creation Styles are mostly clustered with a lot of creative players combining reasonable quality with quantity. Ken Sema, Elias Andersson and Yoshimar Yotún (who left Malmö for the MLS in the summer) are the extremes when it comes to creation volume, while Andreas Vindheim has created some very good chances for Malmö.

Attacking Production

07.pngBy combining goals and assists into Attacking Production we see that Besara was the most productive player when it comes to raw numbers, but when factoring in playing time, Stefanelli once again tops the table in both expected and actual output. Prodell has done well considering his playing time, as well as Malmö’s Alexander Jeremejeff who’s second behind Stefanelli in xG+A per 90 minutes.

Djurgården’s both wingers break into the Total Chance Production table, with Othman El Kabir joining Eriksson just below the top trio. Paulinho was the most productive attacking player though, creating over 5 chances per 90 minutes for Häcken.

08.pngLooking at actual and expected output, we see how most strong attacking players like Besara, Jebali, Homberg, Eriksson, Hysén and Stefanelli tend to perform close to what we can expected. Eliasson is again overperforming while Rosenberg is doing the opposite. Eric Larsson is worth a special mention here as he has produced some fine numbers for a fullback, with his underperformance coming largely from his teammates in Sundsvall underperforming on the chances he created for them.

09.pngSeperating Expected Goals and Expected Assists let us see how the attacking players specialise. Once again we see how this season has really lacked many strong specialist, with only Stefanelli and Sema really standing out on their ends. Most players tend to cluster somewhat here as well, combining creativity with being at the end of chances as well.

Player Profiles

As I now work with StrataData, I’d thought I’d do a total revamp of the popular player maps. The style is more or less shamelessly stolen from a range of other analysts, no names mentioned, and now also include Chance Creation Maps:

K. Holmberg_chanceAs mentioned earlier, Kalle Holmberg was this season’s strongest goalscorer, and from his Chance Map it’s easy to see why: he usually gets into some very good positions just in front of goal, with an average xG of 0.19 per chance. 13 open play goals is strong, but as I’ve also mentioned I think he could’ve done even better had IFK Norrköping’s performance not dropped (and Niclas Eliasson not left).

M. Eriksson_chanceM. Eriksson_creationOperating from Djurgården’s right wing, Magnus Eriksson was another strong goalscorer this season, though a bit more versatile as he also provided a lot of assists for his team. Mostly crosses from the right flank but also two shot rebounds. His Chance Map is a bit different from Holmberg’s with more chances outside the box, which is only natural as he’s after all a midfielder. Though attacking is certainly his main quality, Djurgården will also miss his work ethic, grit and competitiveness now that he’s left for the MLS.

T. Hysén_chanceT. Hysén_creationVeteran Tobias Hysén continues to be extremely important to IFK Göteborg’s attack. His Chance Map combines a lot of good chances inside the box with some poorer outside, some of them direct free kick. When it comes to Chance Creation he’s provided some crucial passing inside and into the box, as well as some corners and free kicks.

N. Besara_chanceN. Besara_creationÖrebro’s Nahir Besara was also extremely important to his team’s attack, combining some chances inside the box with a lot of shooting from outside, including one goal from a direct free kick. His creation numbers are boosted by three rebounds who turned into goals, otherwise it’s mostly corners and crosses into the box.

N. Stefanelli_chanceNicolás Stefanelli arrived at AIK at a crucial time this summer, with the team’s attack struggling during the first half of the season. The Argentinian took some time to adopt but slowly turned into to a real strong presence up front, scoring 9 goals from 14 starts. It will be very interesting indeed to see if he can continue his fine performance come the new season. As a Djurgården supporter, I sure hope not.

L. Hallenius_chanceLinus Hallenius is an interesting case that’s flown under at least my radar this season. With 7 goals and nearly 10 xG he’s done well for a struggling Sundsvall side that just barely managed to stay up. Most of his chances have been created by Eric Larsson, so it’ll be very interesting to see if Hallenius can continue his fine performance next season with the right back having left for champions Malmö.

S. Lundevall_creationElfsborg’s Simon Lundevall was the assist king this season at 12, with 4 of them coming from corners, curiously with some rather high xA values – 3 of them are above 0.30 xA. Maybe Elfsborg have some corner strong routine going on? Lundevall has also provided some long range passes on the left half of the pitch, which I guess is related to counter-attacking.

N. Eliasson_creationNiclas Eliasson’s strong first half of a season earned him a move abroad, and as mentioned earlier IFK Norrköping never really looked the same after that. Overperfoming, sure, but he did create some really good chances for his team with his precise crossing from both flanks.

K. Sema_creationKen Sema was another creation monster, racking up some really good chances with an average xA per chance of 0.18. It’s clear to see why, as most of his passes was either directly inside the box, or ending up in it – a direct consequence of Östersund’s heavily passing-oriented style of attack.

K. Källström_creationThough it stopped at just one season before he chose to end his career, Kim Källström’s long-awaited return to Djurgården was (despite some very inconsistent perfomances) instrumental in returning the team he once won the league with in two consecutive seasons at the start of the millenium, back to the top 3. When he was at his best this season, sitting back in his deep-lying playmaker role he dictated much of Djurgården’s attack with his quarter-back ‘Hail Mary’ style of long passing. Interestingly though, all his assists came from set pieces where he got more time to use his precise left foot.

E. Larsson_creationI mentioned Eric Larsson before and looking at his Chance Creation Map we see clearly how strong a player he is. From his right back position at struggling Sundsvall he produced 52 chances and well over 6 xA – more than most midfielders. Though his teammates only managed to score twice on these chances, with his move to Malmö I expect him to get a lot more assists next season.

That’s it, thank you for reading the whole piece. If you want to see any more Player Chance/Creation Maps, just let me know on Twitter.

This article was written with the aid of StrataData, which is property of Stratagem Technologies. StrataData powers the StrataBet Sports Trading Platform, in addition to StrataBet Premium Recommendations.

Allsvenskan 2017 Summary Part 2

Allsvenskan 2017 Summary

With the end of the Swedish football season I’m now on vacation, and thus have time to do some writing. I haven’t written anything for a while and have especially avoided football since I’m biased with my work involving taking bets on the Swedish leagues. If I say Team X is underrated and should have a good chance of picking up some points in the future, why would you believe me, when I profit from your losses? Once the new season starts I’ll likely crawl back under my rock again, but for now, let’s get to it: Allsvenskan 2017 Summary!

Before we start though, I’d like to point out two things: a) most of the graphics shown below are very much inspired by (or more or less copied from) the great Ben Mayhew at Experimental 361, and b) the data used is from my good friends at Stratagem, for which I used to cover Norwegian Eliteserien and collect stats watching matches. You’ll find more information about Stratagem and their products at the bottom of this piece.

So, Allsvenskan 2017 it is then. First let’s have a look at the final table, once again topped by Malmö who managed to defend their title from last season, making it their 5th since 2010.

01

To my own personal joy, Djurgården finally returned to the top 3 for the first time since 2007, grabbing the last European qualifier spot in the process. Much hyped Östersund also managed to climb from last season’s 8th place, at the same time adding a very impressive run in the Europa League. Häcken have also improved (with new manager Stahre now leaving for the MLS), while Norrköping, IFK Göteborg and Elfsborg have all dropped somewhat. Of the three newcomers, only Sirius managed to stay up, reaching an impressive 7th place after a strong spring and a weaker autumn. Besides Halmstad and AFC Eskilstuna, Jönköpings Södra were also relegated via play-off against the 3rd placed team in Superettan, Trelleborg.

Let’s dig deeper by looking at some scatterplots (note: as I now use data from Stratagem, shots have turned into chances as this is what they collect. For more info, read this blog by Dave Willoughby).

02

Right away we can see part of why Malmö have dominated the season, as they create far more chances than the rest while at the same time keeping a tidy defense and facing fewest chances in the league. There’s quite some distance to the other top teams and interestingly IFK Göteborg seems to have done better chance-wise than the table suggests.

At the other end of things, AFC Eskilstuna stands out as a really poor team with the lowest number of chances created coupled with the highest number of chances faced per match. Jönköpings Södra also stand out a bit, with quite low numbers on both scales indicating some very boring matches (which I can confirm).

03

Looking at attacking effectiveness  we see how the top teams were efficient with their many chances created, while bottom teams like Sundsvall and relegated Halmstad both struggled to create and to capitalise on their chances. A curious case is Elfsborg who were the most efficient scorers, needing less than 7 chances per goal, while at the same time failing to create enough chance volume to compete with the top teams.

04.png

When it comes to defensive effectiveness, AIK and Häcken really stands out with around 13 chances faced per goal conceded, compared to the league average just under 9. Followers of Allsvenskan won’t be surprised to see AIK in the top here as a tight defense has been a cornerstone of the club for a long time. Häcken though, have really been transformed from a care-free attacking-minded side under Peter Gerhardsson, to a more cynic and well-structured defensive side under departing (and former AIK manager) Mikael Stahre. It will be very interesting to see who replaces him and what direction the club will take in the future.

Another interesting point to make is that as affective as they are on the attack, Elfsborg are equally ineffective when defending. With the third most goals scored and most conceded, the Borås side have certainly been entertaining to watch this season.

05

When it comes to Expected Goals, champions Malmö are closely followed by AIK, with Östersund and Djurgården some distance away. AFC Eskilstuna and Elfsborg were the two poorest defenders with around 2 xG conceded per match. I wonder how Elfsborg would have done without their effective scoring?

06

Rating the teams by Expected Goal Difference sees really how close AIK were to Malmö, whose ability to win close matches seems to be a big factor in their title win this season. At the bottom AFC Eskilstuna clearly deserved to be relegated with the worst xG difference, as did Halmstad while Jönköpings Södra maybe deserved a better fate than to be relegated via play-off.

That’s it for now, next up I’m hoping to have a look at individual player’s performance.

This article was written with the aid of StrataData, which is property of Stratagem Technologies. StrataData powers the StrataBet Sports Trading Platform, in addition to StrataBet Premium Recommendations.

Allsvenskan 2017 Summary

Stake sizing, Part 1

In the last post we used Python code to take a look at a classic gambling situation, the coin flip, to make a point about the importance of choosing the highest odds available to bet at. Today, we’ll again use the coin flipping example to investigate another fundamental principal of successful gambling: stake sizing.

Now, imagine we’re one of the lucky punters from the last post who were allowed to bet on a fair coin flip at odds of 2.03. As I stated then, this is pretty much like a license to print money – but how much of your bankroll should you bet on each flip of the coin? Knowing that the coin was indeed fair and you would be getting the best of it, a natural instinct could be to bet as much as you could possibly cough up, steal and borrow in order to maximize your profit. This is a poor strategy though, as we’ll soon come to see.

The reason for this is that even if we do have come across a profitable proposition, our edge when betting at a (I’ll empasize it again: fair) coin flip at 2.03 odds is only 1.5% – meaning that for each 1 unit bet we are expected to net 0.015 units on average. This conclusion should be absolute basics for anyone interested in serious gambling, but to make sure we’re all on the same page I’ll throw some maths at you:

The Expected Value, or EV, of any bet is, simply put, the sum of all outcomes multiplied by their respective probabilities – indicating the punter’s average profit or loss on each bet. So with our coin flip, we’ll win a net of 1.03 units 50% of the time and lose 1 unit 50% of the time; our EV is therefore 1.03 * 0.5 + (-1 * 0.5) = 0.015, for a positive edge of 1.5% and an average profit of 0.015 units per bet. For these simple types of bets though, an easier way to calculate EV is to divide the given odds by the true odds and subtract 1: 2.03 / 2.0 – 1 = 0.015.

An edge of only 1.5% is nothing to scoff at though, empires has been built on less, so we’ll definitely want to bet something – but how much?

Stake sizing is much down to personal preferences about risk aversion and tolerance of the variance innately involved in gambling, but with some Python code we can at least have a look at some different strategies before we set out to chase riches and glory flipping coins. Just like in the last post I’ll just give you the code with some comments in it, which will hopefully guide you along what’s happening  before I briefly explain it.

Here we go:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

def coin_flips(n=10000,odds=1.97,bankroll=100,stake=1,bankrupt=False):
    '''
    Simulates 10000 coinflips for a single punter, betting at 1.97 odds,
    also calculates net winnings

    NEW: default bankroll and stake set at 100 and 1, respectively
    now also calculates if player went bankrupt or not
    '''

    # create a pandas dataframe for storing coin flip results
    # and calculate net winnings
    df = pd.DataFrame()
    # insert n number of coinflips, 0=loss, 1=win
    df['result'] = np.random.randint(2,size=n)
    # calculate net winnings
    df['net'] = np.where(df['result']==1,stake*odds-stake,-stake)
    # calculate cumulative net winnings
    df['cum_net'] = df['net'].cumsum()

    # calculate total bankroll
    df['bankroll'] = df['cum_net'] + bankroll

    # if bankroll goes below the default stake, punter will stop betting
    # count times bankroll < stake
    df['bankrupt'] = np.where(df['bankroll']<stake,1,0)
    # count cumulative bankruptcies, with column shifted one step down
    df['bankruptcies'] = df['bankrupt'].cumsum().shift(1)
    # in case first flip is a loss, bankruptcies will be NaN, replace with 0
    df.fillna(0,inplace=True)
    # drop all flips after first bankruptcy
    if bankrupt:
        df = df[df['bankruptcies']==0]

    return df

First off, we’ll modify our original coin_flips function to take our punter’s bankroll and stake size into consideration, setting the bankrupt threshold at the point where a default sized bet can no longer be made. By default, our punter will have an endless stream of 100 unit bankrolls, but if we set the parameter bankrupt to True, the function will cut away any coin flips after his first bankruptcy.

def many_coin_flips(punters=100,n=10000,odds=1.97,bankroll=100,stake=1,color='r',plot=False,bankrupt=False):
    '''
    Simulates 10000 coinflips for 100 different punters,
    all betting at 1.97 odds,
    also calculates and plots net winnings for each punter

    NEW: now also saves punter bankruptcies
    '''

    # create pandas dataframe for storing punter results
    punter_df = pd.DataFrame()
    # loop through all punters
    for i in np.arange(punters):
        # simulate coin flips
        df = coin_flips(n,odds,bankroll,stake,bankrupt)
        # calculate net
        net = df['net'].sum()
        # check for bankruptcy
        bankruptcy = df['bankrupt'].sum()

        # append to our punter dataframe
        punter_df = punter_df.append({'odds':odds,
                                      'net':net,
                                      'bankrupt':bankruptcy},ignore_index=True)

        if plot:
            # plot the cumulative winnings over time
            df['cum_net'].plot(color=color,alpha=0.1)

    # check if punters ended up in profit
    punter_df['winning'] = np.where(punter_df['net']>0,1,0)

    return punter_df

We also want to modify the many_coin_flips function so that it’ll also take bankroll and stake size into consideration, counting up how many of our punters went bankrupt.

We won’t use the compare_odds function here, instead we’ll write a new one to compare stake sizing – but if we ever want to use it again sometime in the future a few minor changes will be needed here as well:

def compare_odds(punters=100,n=10000,odds=[1.97,2.00,2.03]):
    '''
    Simulates and compare coin flip net winnings
    after 10000 flips for 3 groups of punters,
    betting at odds of 1.97, 2.00 and 2.03, respectively.
    Also plots every punters net winnings
    '''

    # create figure and ax objects to plot on
    fig, ax = plt.subplots()

    # set y coordinates for annotating text for each group of punters
    ys = [0.25,0.5,0.75]
    # assign colors to each group of punters
    cs = ['r','y','g']

    # loop through the groups of punters, with their respective odds,
    # chosen color and y for annotating text
    for odd, color, y in zip(odds,cs,ys):
        # run coin flip simulation with given odds, plot with chosen color
        df = many_coin_flips(punters,n,odd,color=color,plot=True)
        # calculate how many punters in the group ended up in profit
        winning_punters = df['winning'].mean()
        # set a text to annotate
        win_text = '%.2f: %.0f%%' %(odd,winning_punters * 100)
        # annotate odds and chance of profit for each group of punters
        ax.annotate(win_text,xy=(1.02,y),
                    xycoords='axes fraction', color=color,va='center')

    # set title
    ax.set_title('Chances of ending up in profit after %s coin flips' %n)
    # set x and y axis labels
    ax.set_xlabel('Number of flips')
    ax.set_ylabel('Net profit')
    # add annotation 'legend'
    ax.annotate('odds: chance',xy=(1.02,1.0),
                xycoords=('axes fraction'),fontsize=10,va='center')
    # add horizontal line at breakeven point
    plt.axhline(color='k',alpha=0.5)
    # set y axis range at some nice number
    ax.set_ylim(-450,450)

    # show plot
    plt.show()

Now, with all our previous coin flip functions taking bankroll and stake size into consideration, we can go ahead and evaluate a few stake sizing strategies with a new function:

def compare_stakes(punters=200,n=10000,odds=2.03,stakes=[100,50,25,10,5,2,1,0.5],bankroll=100):
    '''
    Similar to compare_odds, but here we instead want to compare different
    staking sizes for our coin flips betting at 2.03 odds

    Increased number of punters in each group, from 100 to 200

    Also prints out the results
    '''

    # pandas df to store results
    results_df = pd.DataFrame(columns=['stake','win','lose','bankrupt'])

    # colors to use in plot later, green=1=win, yellow=4=lost, red=2=bankrupt
    colors = [sns.color_palette()[i] for i in (1,4,2)]

    # loop through the groups of punters, with their respective odds
    for stake in stakes:
        # run coin flip simulation with given stake
        df = many_coin_flips(punters,n,odds,stake=stake,bankrupt=True)
        # calculate how many punters in the group ended up in profit
        winning_punters = df['winning'].mean()
        # ...and how many went bankrupt
        bankrupt_punters = df['bankrupt'].mean()
        # lost money but not bankrupt
        lose = 1 - winning_punters - bankrupt_punters

        # append to dataframe
        results_df = results_df.append({'stake':stake,
                                        'win':winning_punters,
                                        'lose':lose,
                                        'bankrupt':bankrupt_punters},ignore_index=True)

    # set stake as index
    results_df.set_index('stake',inplace=True)

    # plot
    fig = plt.figure()
    # create ax object
    ax = results_df.plot(kind='bar',stacked=True,color=colors,alpha=0.8)
    # fix title, axis labels etc
    ax.set_title('Simulation results: betting %s coin flips at %s odds, starting bankroll %s' %(n,odds,bankroll))
    ax.set_ylabel('%')
    # set legend outside plot
    ax.legend(bbox_to_anchor=(1.2,0.5))

    # add percentage annotation for both win and bankrupt
    for x, w, l, b in zip(np.arange(len(results_df)),results_df['win'],results_df['lose'],results_df['bankrupt']):
        # calculate y coordinates
        win_y = w/2
        lost_y = w + l/2
        bankr_y = w + l + b/2

        # annotate win, lose and bankrupt %, only if >=2%
        if w >= 0.04:
            ax.annotate('%.0f%%' %(w * 100),xy=(x,win_y),va='center',ha='center')
        if l >= 0.04:
            ax.annotate('%.0f%%' %(l * 100),xy=(x,lost_y),va='center',ha='center')
        if b >= 0.04:
            ax.annotate('%.0f%%' %(b * 100),xy=(x,bankr_y),va='center',ha='center')

    plt.show()

By default, our new compare_stakes function creates a number of punter groups, all betting on fair coin flips at 2.03 odds with a starting bankroll of a 100 units. For each group and their different staking plan, the function takes note of how many ended up in profit, how many lost and how many went bankrupt.

As we can see on the plot below, the results differ substantially:

01

Just like last time, I want to remind you that any numbers here are only rough estimates, and increasing the size of each punter group as well as the number of coin flips will get us closer to the true values.

So what can we learn from the above plot? Well, the main lesson is that even if you have a theoretically profitable bet, your edge will account for nearly nothing if you are too bold with your staking. Putting your whole bankroll at risk will see you go bankrupt around 96% of the time, and even if you bet as small as 2 units, you’ll still face a considerable risk of screwing up a lucrative proposition. The truth is that with such a small edge, keeping your bet small as well is the way to go if you want to make it in the long run.

But what if some fool offered us even higher odds, let’s say 2.20? First off, we would have to check if the person was A: mentally stable, and B: rich enough to pay us if (or rather, when) we win, before we go ahead and bet. Here our edge would be 10% (2.2 / 2.0 – 1), nearly 10 times as large as in the 2.03 situation, so we’ll likely be able to bet more – but how much? Well, the functions are written with this in mind, enabling us to play around with different situations and strategies. Specifying the odds parameter of our new function as 2.20, here’s what betting at a fair coin flip at 2.20 odds would look like:

02

As can be seen from the new plot, with a larger edge we can go ahead and raise our stake size considerably, hopefully boosting our winnings as well. So the main take-away from this small exercise is that even if you have an edge, if you want to make it in the long run you’ll have to be careful with your staking to avoid blowing up your bankroll – but also that the larger your edge, the larger you can afford to bet.

That’s it for now, but I’ll hopefully be back soon with a Part 2 about stake sizing, looking at a staking plan that actually takes your (perceived) edge into account when calculating the optimal stake size: The Kelly Criterion.

Stake sizing, Part 1

Flipping coins, and the importance of betting at the highest odds

As I stated in the previous post, this blog will now focus more on gambling, using Python code to investigate whatever comes to my mind around the subject.

Today I’ll have a look at a classic gambling example – the flip of a coin – but before I go ahead and talk you through the code I want to state a few things that I know some of you will be wondering. Though R seems to be the language preferred by most in the football analytics scene, I have chosen Python simply because I feel it is so much more intuitive and easier to learn. RStudio seems to be the tool of choice for the R folks, but I don’t know of any real dominant counterpart for Python. I use Spyder, available through downloading Anaconda, mainly because it’s easy to use and comes with a lot of useful stuff pre-installed. If you’re thinking about testing it out yourself, I would suggest switching the color scheme of the editor to Zenburn for that dark and cool programming look that really make your code look super important, and run your scripts in the included IPython console.

One final, very important thing: I am not in any way an expert programmer, statistician, mathematician or anything like that. I am simply a gambler looking to use these fields to get an edge. It’s totally OK to simply copy and paste any code I publish here to use yourself and play around with it however you may wish. If you notice any mistakes or if something doesn’t add up, please comment. I’m happy to learn new stuff.

Flipping coins, and the importance of betting at the highest odds

The inspiration for this post came the other day when I noticed that a few hours prior to kick-off in this year’s Super Bowl, the bookmaker Pinnacle offered 1.97 odds on the opening coin flip. A sucker bet, I thought to myself, knowing the true odds of a fair coin to be 2.00. The coin flip is a very popular Super Bowl prop bet though and as it was pointed out to me on Twitter, a few books actually offered the fair odds of 2.00. Choosing the highest odds available is crucial if you want to make money gambling in the long run, so I decided to write up a nice little Python script to visualise my point.

The layout of these blog posts will be that I simply throw a piece of code at you, before explaining it. The comments in the code itself should also help you out, and for those of you who already know Python much will be simple basics, while those who’s completely new to coding or Python will hopefully learn a few things.

Here we go:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

def coin_flips(n=10000,odds=1.97):
    '''
    Simulates 10000 coinflips for a single punter,
    betting at 1.97 odds,
    also calculates net winnings
    '''

    # create a pandas dataframe for storing coin flip results
    # and calculate net winnings
    df = pd.DataFrame()
    # insert n number of coinflips, 0=loss, 1=win
    df['result'] = np.random.randint(2,size=n)
    # calculate net winnings
    df['net'] = np.where(df['result']==1,odds-1,-1)
    # calculate cumulative net winnings
    df['cum_net'] = df['net'].cumsum()

    return df

Allright, so after importing all the needed modules for this piece, we go ahead and define our first function, coin_flips, which will be used to simulate the coin flips and calculate the net winnings of a single punter. I’ve chosen 10,000 flips and Pinnacle’s odds of 1.97 as our default values here.

Creating a pandas dataframe, we can easily store the result of each coin flip. Now, as we assume that the coin is fair, there’s no need to even consider which side our punter would call each time, instead we can simply go ahead and use numpy to simulate a series of ones and zeros, representing either a win or a loss. Calculating the net result of each flip is also very straightforward as when he wins, our punter will pocket the net end of the offered odds, 0.97, while losing will see his pocket lightened by 1 unit. Calculating the cumulative net winnings is also very easy using pandas’ built-in cumsum function.

For coding reasons, the function is set to return the dataframe so calling it will simply make a lot of numbers pop up, but running the coin_flips()[‘cum_net’].plot() command in the IPython console will let you simulate a punter’s coin flips, and also plot his cumulative net winnings like this:

01

Every time you run the command another simulation will run with a new, different result. Doing this a couple of times, you’ll likely understand why I described this as a sucker bet. Sure, you can get lucky and win, even a couple of times in a row – but betting with the odds against you, you’ll find it very hard to make a profit long term.

But that single punter flipping coins 10,000 times actually doesn’t say that much, maybe he just got unlucky? To dig deeper we want to know just how likely you are to end up with a profit after 10,000 coin flips. So we write another function, using the previous one to simulate the results of many more punters betting on 10,000 coin flips. How many do you think will end up in profit?

def many_coin_flips(punters=100,n=10000,odds=1.97,color='r'):
    '''
    Simulates 10000 coinflips for 100 different punters,
    all betting at 1.97 odds,
    also calculates and plots net winnings for each punter
    '''

    # create pandas dataframe for storing punter results
    punter_df = pd.DataFrame()
    # loop through all punters
    for i in np.arange(punters):
        # simulate coin flips
        df = coin_flips(n,odds)
        # calculate net
        net = df['net'].sum()
        # append to our punter dataframe
        punter_df = punter_df.append({'odds':odds,
                                      'net':net},ignore_index=True)

        # plot the cumulative winnings over time
        df['cum_net'].plot(color=color,alpha=0.1)

    # check if punters ended up in profit
    punter_df['winning'] = np.where(punter_df['net']>0,1,0)

    return punter_df

The slightly more complicated many_coin_flips function uses the earlier coin_flips to loop through a group of punters, 100 by default, and save their results into a new pandas dataframe, punter_df, where we’ll assign a 1 to all punters who ended up in profit while all the losers get a 0. We also plot each punters cumulative net winnings with a nice red color to symbolise their (very) likely bankruptcy.

This function also returns a dataframe so running it will again make a lot of numbers pop up in the console, but it also plots out the financial fate of each punter, like this:

02.png

As we can see, there actually are a few of our 100 punters who got lucky enough to end up winning after 10,000 coin flips. But most of them ended up way below the break-even point, losing a lof of money. If this was a real group of punters we can only hope that even if they were stupid enough to set out betting on 10,000 coin flips at these odds, they’ll at least at some point realise their mistake and quit.

But how about if we change the offered odds? As I mentioned earlier, some books actually put up the fair odds of 2.00. How would 100 punters do after 10,000 coin flips betting at those odds? Well, we’ll have to write a new function for that. Also, just for fun (or to make a point) I’ve included an additional group of 100 punters lucky enough to be allowed to bet on the coin flips at odds of 2.03 – literally a license to print money.

def compare_odds(punters=100,n=10000,odds=[1.97,2.00,2.03]):
    '''
    Simulates and compare coin flip net winnings
    after 10000 flips for 3 groups of punters,
    betting at odds of 1.97, 2.00 and 2.03, respectively.
    Also plots every punters net winnings
    '''

    # create figure and ax objects to plot on
    fig, ax = plt.subplots()

    # set y coordinates for annotating text for each group of punters
    ys = [0.25,0.5,0.75]
    # assign colors to each group of punters
    cs = ['r','y','g']

    # loop through the groups of punters, with their respective odds,
    # chosen color and y for annotating text
    for odd, color, y in zip(odds,cs,ys):
        # run coin flip simulation with given odds, plot with chosen color
        df = many_coin_flips(punters,n,odd,color)
        # calculate how many punters in the group ended up in profit
        winning_punters = df['winning'].mean()
        # set a text to annotate
        win_text = '%.2f: %.0f%%' %(odd,winning_punters * 100)
        # annotate odds and chance of profit for each group of punters
        ax.annotate(win_text,xy=(1.02,y),
                    xycoords='axes fraction', color=color,va='center')

    # set title
    ax.set_title('Chances of ending up in profit after %s coin flips' %n)
    # set x and y axis labels
    ax.set_xlabel('Number of flips')
    ax.set_ylabel('Net profit')
    # add annotation 'legend'
    ax.annotate('odds: chance',xy=(1.02,1.0),
                xycoords=('axes fraction'),fontsize=10,va='center')
    # add horizontal line at breakeven point
    plt.axhline(color='k',alpha=0.5)
    # set y axis range at some nice number
    ax.set_ylim(-450,450)

    # show plot
    plt.show()

This last function makes use of the two previous ones to simulate the coin flips of our three groups of punters, plotting their total net winnings all on the same ax object, which we later make use of to add a title and some nice labels to the axes. We also add a horizontal line to be able to better compare the punters’ winnings with the break-even point, as well as some text annotation to explain the colors of the three groups.

Now, running the compare_odds() function in the IPython console will hopefully result in something like this:

03

Here we clearly see just how important betting at the highest odds really is. Have in mind though that the numbers to the right are only rough estimates. As you can see, the yellow group of punters who bet at the fair odds of 2.00 did not win exactly 50% of the time, but close enough. I actually had to re-run the function a few times to get this close. But it’s only natural since we only had 100 punters, a very small number in this context, in each of our groups. The more punters and coin flips we use in our simulations, the closer we’ll come to the real win percentages – but here speed is more important than super accuracy.

So as we clearly see in the above plot, betting on the coin flip at Pinnacle’s 1.97 odds really is a sucker bet, albeit an entertaining one if you were planning to watch the Super Bowl. But if you hope to make a profit from your betting, finding the highest available odds to bet on is crucial, as is shown by the green group of punters who were allowed to bet at odds of 2.03. It’s only a difference of 0.06, but it makes all the difference in the long run. The margins in betting are tiny, but they add up over time.

The lessons learned here can easily be transferred to sports betting in general and football betting in particular, were the Asian Handicaps and Over/Under markets focus on odds around even money. The coin flip example is special though as we knew the true odds of the bet beforehand, something you’ll never be able to know betting on football. But as shown in the last plot, by consistently betting at the highest available odds, you at least give yourself a much better chance of ending up in profit.

Flipping coins, and the importance of betting at the highest odds

With a new season approaching, the blog changes course: Gambling, probability and programming!

As you may have noticed, I haven’t written anything in months. There’s two reasons for this, one being of course that the Swedish football season I’ve primarily focused on ended in November, but it’s also because I’ve taken on a new job. Working full time for the first time in my life has simply left me with little time to do any writing. (Yes, I did use the word time three times in that short sentence.)

But now, having settled in at the new job I’m anxious to get back to writing again. There’s one thing though: as I now work with compiling odds on Swedish football I wouldn’t feel comfortable publishing football analytics about Allsvenskan, telling you which teams are underrated and who’ll win the league title. And knowing I set the odds, and potentially profit from your mistakes, why would you believe anything I said?

So this blog will take on a slightly new focus: gambling. I originally set up the blog intending to write about this topic as well as football analytics, using maths, statistics, probability and psychology to discuss interesting things related to gambling, but the football part soon took over completely.

As I’ve published my football work on the blog I’ve now and then gotten some questions about programming, so I’ve taken the decision to include Python code whenever applicable. Learning to code has made a huge difference for me both in my gambling and football analytics endeavours, and though the blog won’t turn into a Python tutorial per se, if any of you who are new to programming should learn a new thing or two through my writing, I’d be glad.

I’m still hoping to write the occasional football analytics piece though, and if I do it’ll likely be for StrataBet, using their data as I did when I had a look at headers in Allsvenskan and Norway’s Tippeligaen.

That’s it for now, but I already have a new post in the works, coming up very shortly!

With a new season approaching, the blog changes course: Gambling, probability and programming!

Allsvenskan 2016 summary pt. 2

A week ago I published the first part of – hopefully – three Allsvenskan 2016 summaries, then focusing on team performance. Now it’s time to have a look at individual players, much like I did back in July. Though there now exists detailed Opta data for Allsvenskan, my work on this site has mostly been based on the older, less detailed data sources focused on shots and thus this summary will only look at attacking players.

I’ve again had a look at Goal Contribution (goals+assists) and Expected Goals, dividing all players into three age groups, and also had a closer look at a few interesting players:

01

02.png

The Goal Contribution chart is unsurprisingly headed by Häcken’s John Owoeri who clinched the title as the league’s top scorer with his 4 goals against Falkenberg in the last round of the season. Interestingly, Owoeri only came alive in the second half of the season, scoring 15 of his 17 goals after the summer break.

03

 

Assist monster Magnus Wolff Eikrem sits in second, with his 0.71 assists per 90 minutes playing a big part in Malmö retaking the title. Of the other top players, Antonsson, Kjartansson and Nyman left the league during the summer transfer window but still impressed enough during the spring to remain in the top 10.

 

Djurgården’s Michael Olunga sits top among the players aged 20-23. Dubbed ‘The Engineer’ for his ongoing studies, Olunga just like Owoeri needed time to get going, scoring all of his 12 goals during the last 13 games when Mark Dempsey came in to steer Djurgården away from the relegation battle.

04

Comparing Owoeri and Olunga, it’s clear from the shot maps why Owoeri was the superior goalscorer this season. He only shoots slightly more than Olunga, but does so from far better locations closer to goal, with his average xG per shot at 0.16 while Olunga at 0.12 rely more on his finishing skill from longer range. If ‘The Engineer’ can work on his shot selection for next season I really think he can challenge for the top scorer title.

 

AIK’s Alexander Isak reign supreme among the youngest players, with his 0.62 G+A90 very impressive for a player who only turned 17 late in the season. He’s quite good at getting into good shot locations as well, with 5 of his 10 goals coming from a sweet spot just in front of goal.

05

There’s been plenty of rumours of an upcoming big transfer during the winter window and looking very much like the real deal, Isak could very well break Zlatan Ibrahimovic’s transfer record from 2001. Here’s a nice radar plot from Ted Knutson showing Isak’s skills:

 

Malmö’s Vidar Kjartansson was the king of xG this season, and the club impressingly still managed to secure the title after selling him during the summer transfer window. Kjartansson combined both quantity with quality, taking most of his shots from very good locations with an average xG per shot of 0.2.

06

 

Östersund’s Abdullahi Gero was a bit of a surprise for me, but his shot locations are good with an average xG per shot close to Kjartansson at 0.19. He could very well go on to score more next season if given the chance in Graham Potter’s Östersund side which have done so well xG-wise this season – actually finishing 4th in xG Difference per game!

07

 

As a Djurgården supporter I’m glad to see 20-year old Tino Kadewere’s development this season. Though his 793 minutes played was less than the 900 needed to be included above, he racked up an impressing 0.79 G+A90 which would see him sit 8th overall, just above Olunga, and top the players aged 20-23 if the cut-off would have been 1/4 of the league minutes played instead of 1/3. Focusing more on assists than Olunga, the two could form a dynamic partnership for Djurgården if they get the chance next season.

 

That’s it for now, but if you want to see more shot maps, just give me a shout on twitter. If I’ll find the time, I’ll also write a third summary looking at how my predictions have done over the season and how my model did against the betting markets.

Allsvenskan 2016 summary pt. 2