Kalman Filter Model for European Club Competitions

The model behind the European club Kalman ratings is the one developed for the NBA in 2011, adapted to a very different setting. The idea itself is simple. Every team has a hidden strength that drifts over time. The strengths are never seen directly, only the scores of the games, which depend on the difference between the two teams' strengths plus quite a lot of randomness. The Kalman filter turns the stream of scores into running estimates of the strengths, together with a measure of how uncertain those estimates are.

The NBA is one league of 30 teams that all play each other. The model describing European club basketball consists of 54 competitions: the EuroLeague, the EuroCup, the Basketball Champions League, the FIBA Europe Cup and the ENBL, together with domestic first and second divisions and regional leagues such as the ABA League. Most of the games are played within domestic leagues.

The European club teams form a really interesting network where the leagues are linked together by the clubs that also play in a European competition, and by promotion and relegation between divisions. Home courts, playing styles and the level of competitiveness also differ from league to league.

The model therefore has three modifications. Time is measured in calendar days, with an extra change between seasons. Each competition has its own home-court advantage and its own game-to-game randomness. A club entering the data starts at the average level of its league, and a league entering the data gets an unknown level of its own.

State-space model

Consider the clubs in the data. The state at time \(t\) is the vector \(\mathbf{x}_t\), whose element \(x_t(i)\) is the strength, or rating, of club \(i\). The strength of a club depends on players developing and declining by age, injuries and recovery, roster changes, coaching, and plenty of intangibles. Instead of modelling any of these explicitly, the model treats their combined effect as random noise:

\[ \mathbf{x}_t = \mathbf{x}_{t-1} + \mathbf{w}_t, \qquad \mathbf{w}_t \sim N(\mathbf{0}, \mathbf{M}_t). \tag{1} \]

There is no trend: the best guess for tomorrow's strength is today's strength. In the thesis, \(t\) counted the game days of one NBA season and \(\mathbf{M}_t = \sigma_w^2 \mathbf{I}\). A European season runs from September to June, and clubs play one to three games a week, in one or two competitions. Time is therefore measured in calendar days, with an extra change at the start of each season:

\[ \mathbf{M}_t = \operatorname{diag}\bigl(m_t(1), \ldots, m_t(n)\bigr), \qquad m_t(i) = \sigma_w^2\, \Delta_t(i) + \sigma_J^2\, \mathbf{1}\bigl[\text{club } i \text{ starts a new season}\bigr]. \tag{2} \]

Here \(\Delta_t(i)\) is the number of days since the previous game of club \(i\), \(\sigma_w^2\) is the variance of the change in strength per day, and \(\sigma_J^2\) is the variance of the extra change over the summer, when rosters are rebuilt.

New clubs and new leagues

In the thesis, there was only one league and its every team started the season at zero with variance \(\sigma_0^2\). That does not work here. Games within a league tell how the clubs of that league compare with each other and the games between leagues tell how the leagues compare to other leagues. If a new club is placed at zero when it starts playing, it is going to affect the league's strength relative to other leagues.

Therefore, the model places a new club \(k\) relative to its domestic league \(G\). A club without a domestic league belongs to the competition of its first game. If league \(G\) already has clubs with existing state estimates, the new club starts at their current average:

\[ x_t(k) = \frac{1}{|\mathcal{M}_G|} \sum_{j \in \mathcal{M}_G} x_t(j) + u_k, \qquad u_k \sim N(0, \sigma_u^2), \tag{3} \]

where \(\mathcal{M}_G\) is the set of clubs of \(G\) already with state estimates. If \(G\) is new to the data, its clubs start from a common unknown league level:

\[ x_t(k) = \lambda_G + u_k, \qquad \lambda_G \sim N(0, \sigma_\lambda^2). \tag{4} \]

The league level \(\lambda_G\) is part of the state, so all clubs of a new league move together until games against other leagues pin it down. Equation (3) is exact in the Gaussian sense: with \(\mathbf{a}\) the vector of weights \(1/|\mathcal{M}_G|\) on the league's clubs, the new club has mean \(\mathbf{a}^{\top}\hat{\mathbf{x}}\), variance \(\mathbf{a}^{\top}\boldsymbol{\Sigma}\mathbf{a} + \sigma_u^2\) and covariance \(\boldsymbol{\Sigma}\mathbf{a}\) with the other clubs. Clubs that are promoted or relegated between leagues keep their ratings and they are not considered as "new".

Game scores

The ratings are observed only through game scores. In a game of competition \(c\) between clubs \(i\) and \(j\), the observation \(y_t\) is the point differential, i.e., the points scored by club \(i\) minus the points scored by club \(j\):

\[ y_t = x_t(i) - x_t(j) + \mu_c \cdot h_t + v_t, \qquad v_t \sim N(0, \sigma_{v,c}^2). \tag{5} \]

Here \(h_t = 1\), if club \(i\) plays at home, and \(h_t = 0\), on a neutral court. Games played at neutral courts are rare in Europe: only 0.5% of the games, mostly Final Fours. The home-court advantage \(\mu_c\) and the noise variance \(\sigma_{v,c}^2\) depend on the competition \(c\). A EuroLeague game and a game in the Norwegian league are played in different halls, by teams of different skill level and roster width, so there is no reason to assume they share these values. The noise terms of different games are independent of each other and of the changes \(\mathbf{w}_t\).

Two properties follow directly. First, the ratings are measured in points, because the point differential on the left-hand side is in points. Second, only differences of ratings are observed. Adding the same constant to every rating changes nothing, so the absolute level is a matter of convention.

Kalman filter

The Kalman filter estimates the state recursively, one game at a time. After the games up to time \(t\), everything known about the ratings is summarized by the estimate \(\hat{\mathbf{x}}_{t|t}\) and its covariance matrix \(\boldsymbol{\Sigma}_{t|t}\). The diagonal of \(\boldsymbol{\Sigma}_{t|t}\) tells how uncertain each club's rating is. The off-diagonal elements tell how the errors of different clubs' ratings are linked. A club enters the state through (3) or (4) just before its first game.

Each game then involves two steps. In the prediction step, the ratings stay where they are, but they become more uncertain with time:

\[ \hat{\mathbf{x}}_{t|t-1} = \hat{\mathbf{x}}_{t-1|t-1}, \qquad \boldsymbol{\Sigma}_{t|t-1} = \boldsymbol{\Sigma}_{t-1|t-1} + \mathbf{M}_t. \tag{6} \]

The predicted point differential and its variance are

\[ \begin{aligned} \hat{y}_t &= \hat{x}_{t|t-1}(i) - \hat{x}_{t|t-1}(j) + \mu_c \cdot h_t, \\ O_t &= \Sigma_{t|t-1}(i,i) + \Sigma_{t|t-1}(j,j) - 2\,\Sigma_{t|t-1}(i,j) + \sigma_{v,c}^2. \end{aligned} \tag{7} \]

The variance \(O_t\) has two parts: the uncertainty about the difference of the two ratings and the randomness of a single game in competition \(c\). The winning probability of club \(i\) is \(\Phi(\hat{y}_t / \sqrt{O_t})\), where \(\Phi\) is the standard normal cumulative distribution function.

In the update step, the score is compared with the prediction and the estimates are corrected:

\[ \begin{aligned} d_t &= y_t - \hat{y}_t, \qquad \mathbf{K}_t = \boldsymbol{\Sigma}_{t|t-1} \mathbf{C}_t^{\top} O_t^{-1}, \\ \hat{\mathbf{x}}_{t|t} &= \hat{\mathbf{x}}_{t|t-1} + \mathbf{K}_t d_t, \qquad \boldsymbol{\Sigma}_{t|t} = \boldsymbol{\Sigma}_{t|t-1} - \mathbf{K}_t O_t \mathbf{K}_t^{\top}. \end{aligned} \tag{8} \]

Here \(\mathbf{C}_t\) is the schedule row with \(+1\) for club \(i\), \(-1\) for club \(j\) and zeros elsewhere. The innovation \(d_t\) is the prediction error, i.e., the actual point differential minus the expected one. The Kalman gain \(\mathbf{K}_t\) decides how much the ratings move and in which direction. The two clubs move in opposite directions, and other clubs move as well if their ratings are correlated with either of them.

The correlations carry information across leagues. A domestic league builds up strong correlations among its clubs, because they play each other repeatedly. When a Spanish club beats an Italian club in the EuroLeague by more than expected, the Spanish club moves up and the Italian club moves down, but so do, to a lesser degree, the other clubs of Liga ACB and Lega Basket Serie A.

Estimation of the model parameters

The model has four global parameters, \(\sigma_w^2\), \(\sigma_J^2\), \(\sigma_u^2\) and \(\sigma_\lambda^2\), and two parameters for each of the 54 competitions, \(\mu_c\) and \(\sigma_{v,c}^2\), which results in 112 parameters in total. They are estimated by the maximum likelihood method. Given the games so far, the next point differential is normally distributed with the mean and variance (7), so the log-likelihood is a sum over games:

\[ \ell(\boldsymbol{\theta}) = -\frac{1}{2} \sum_{t} \Bigl( \log(2\pi O_t) + \frac{d_t^2}{O_t} \Bigr), \qquad \hat{\boldsymbol{\theta}} = \arg\max_{\boldsymbol{\theta}} \ell(\boldsymbol{\theta}). \tag{9} \]

The sum runs over the 58,862 games from the 2021-22 season to the start of 2026-27. The season 2020-21 was used as the warmup period for the ratings. The maximum is found with a gradient method and the gradient of \(\ell\) is computed exactly by a backward pass of the filter over the same games. The standard errors come from the curvature of \(\ell\) at its maximum.

Table 1. Global parameters of the model (standard errors in parentheses).
ParameterInterpretationValue
\(\sigma_w^2\)Uncertainty of the change in club strength per day0.0401 (0.0036)
\(\sigma_J^2\)Uncertainty of the change between seasons8.57 (1.09)
\(\sigma_u^2\)Uncertainty of a new club's rating around its league's average81.2 (8.1)
\(\sigma_\lambda^2\)Uncertainty of a new league's level165 (59)

The global estimates have intuitive interpretations. A club's season lasts about 220 days, over which its strength changes with variance \(220 \times 0.0401 \approx 8.8\), i.e., about \(\pm 3.0\) points. The summer break lasts about 140 days, with variance \(140 \times 0.0401 + 8.57 \approx 14.2\), i.e., about \(\pm 3.8\) points. Over a full year, 62% of the change happens between seasons. A new club starts within about \(\pm 9.0\) points of its league's average. The level of a new league is the least precise estimate, because few leagues enter the data after the first season.

Table 2. Home-court advantage \(\mu_c\) (points) and variance of the point differential \(\sigma_{v,c}^2\) by competition, sorted by \(\mu_c\) (standard errors in parentheses). Games = games in the likelihood.
CompetitionGames\(\mu_c\)\(\sigma_{v,c}^2\)\(\sigma_{v,c}\)
Hungarian NB I/A1,3364.84 (0.35)144.0 (6.3)12.0
Greek Elite League1,3004.58 (0.34)126.2 (5.8)11.2
Bosnian Championship9404.52 (0.41)133.8 (7.2)11.6
Slovak Extraliga9074.28 (0.47)176.5 (9.3)13.3
Czech NBL1,3584.15 (0.37)170.8 (7.3)13.1
Serbian First League1,2474.10 (0.35)133.4 (6.2)11.5
Greek Basket League9014.01 (0.39)122.0 (6.6)11.0
Bulgarian NBL9204.00 (0.42)140.1 (7.4)11.8
Primera FEB1,6493.86 (0.31)134.7 (5.4)11.6
Belgian Pro Basketball League1033.81 (1.31)164.8 (24.7)12.8
Montenegrin Prva A Liga7793.79 (0.49)165.4 (9.6)12.9
EuroLeague1,7903.77 (0.28)127.2 (4.7)11.3
Korisliiga1,1833.71 (0.42)183.9 (8.4)13.6
ABA League1,1643.68 (0.35)127.4 (6.0)11.3
Icelandic Úrvalsdeild8383.65 (0.49)179.3 (10.0)13.4
Liga ACB1,6933.63 (0.30)134.2 (5.2)11.6
Cypriot Division A6783.58 (0.50)148.5 (9.3)12.2
Serie A22,3563.55 (0.24)118.2 (4.0)10.9
Swedish Basketligan9753.54 (0.42)156.5 (8.0)12.5
LNB Élite1,5723.49 (0.34)158.6 (6.3)12.6
Slovenian League8013.44 (0.48)166.0 (9.4)12.9
Lega Basket Serie A1,3643.42 (0.33)131.2 (5.7)11.5
Serbian Superleague873.41 (1.70)237.7 (38.1)15.4
Élite 21,8523.39 (0.29)135.4 (5.1)11.6
Macedonian First League9033.36 (0.43)147.5 (8.0)12.1
BNXT League1,6473.34 (0.34)171.1 (6.7)13.1
Basketball Champions League1,0663.32 (0.41)136.3 (6.8)11.7
FIBA Europe Cup1,0673.30 (0.42)157.6 (7.9)12.6
Croatian Premijer Liga1,1223.16 (0.41)172.9 (8.1)13.1
Austrian Superliga1,0093.13 (0.45)182.1 (9.1)13.5
Dutch Basketball League873.11 (1.47)175.5 (28.6)13.2
Latvian-Estonian League1,1942.98 (0.40)165.7 (7.7)12.9
EuroCup1,0662.90 (0.40)149.5 (7.2)12.2
Portuguese LPB8882.88 (0.42)138.5 (7.6)11.8
Romanian Liga Națională1,5002.86 (0.32)139.1 (5.8)11.8
Basketbol Süper Ligi1,3672.85 (0.34)139.6 (6.0)11.8
Turkish TBL1,5472.82 (0.31)127.4 (5.3)11.3
Swiss SB League8172.74 (0.50)182.7 (10.2)13.5
ProA1,6942.71 (0.34)172.9 (6.7)13.1
Basketball Bundesliga1,7062.63 (0.33)164.4 (6.2)12.8
Kosovo Superliga6772.51 (0.52)159.4 (9.8)12.6
Liga Leumit1,2312.32 (0.38)155.2 (7.1)12.5
Super League Basketball8922.29 (0.45)160.3 (8.5)12.7
NKL1,7262.26 (0.32)159.1 (6.0)12.6
Danish Basketligaen9262.25 (0.44)156.1 (8.2)12.5
VTB United League1332.08 (1.16)159.9 (21.8)12.6
ABA League 24732.07 (0.60)149.4 (11.1)12.2
LKL1,0272.06 (0.38)131.7 (6.6)11.5
Israeli Premier League1,0221.96 (0.40)146.1 (7.3)12.1
Polish Basket Liga1,4161.71 (0.35)158.4 (6.7)12.6
Norwegian BLNO9381.39 (0.56)263.7 (13.5)16.2
European North Basketball League3921.34 (0.69)151.4 (12.6)12.3
Ukrainian Superleague7911.18 (0.46)144.1 (8.3)12.0
Georgian Superleague7450.87 (0.49)151.7 (9.1)12.3

The home-court advantage ranges from 0.9 points in Georgia to 4.8 points in Hungary, with a games-weighted average of 3.16. The differences are real, not noise. Under equal home advantages, \(\sum_c \bigl((\hat{\mu}_c - 3.16)/\mathrm{SE}_c\bigr)^2\) would be approximately \(\chi^2\) with 53 degrees of freedom, with 95% of its values below 71. The observed value is 235. The same statistic for the variances is 437.

The randomness of a single game also differs. The standard deviation \(\sigma_{v,c}\) ranges from 10.9 points in Serie A2 to 15.4 points in the Serbian Superleague, while the Norwegian league (16.2 points) could be considered an outlier. The four competitions with fewer than 150 games in the likelihood (the Belgian and Dutch playoffs, the Serbian Superleague, and the last VTB season before the Russians invaded Ukraine) have the least precise estimates.

Next
Next

Kalman Filter Model for NCAA Basketball