|
VAEP |
|
|
|
|
|
VAEP (Valuing Actions by Estimating Probabilities) is based on the insight |
|
that players tend to perform actions with two possible intentions: |
|
|
|
1. increase the chance of scoring a goal in the short-term future and/or, |
|
2. decrease the chance of conceding a goal in the short-term future. |
|
|
|
Valuing an action then requires assessing the change in probability for both |
|
scoring and conceding as a result of an action. Thus, VAEP values a game state as: |
|
|
|
.. math:: |
|
|
|
V(S_i) = P_{score}(S_i, t) - P_{concede}(S_i, t), |
|
|
|
where :math:`P_{score}(S_i, t)` and :math:`P_{concede}(S_i, t)` are the |
|
probabilities that team :math:`t` which possesses the ball in state |
|
:math:`S_i` will respectively score or concede in the next 10 actions. |
|
|
|
The remaining challenge is to "learn" :math:`P_{score}(S_i, t)` and :math:`P_{concede}(S_i, t)`. |
|
That is, a gradient boosted binary classifier is |
|
trained on historical data to predict how a game state will turn out based on |
|
what happened in similar game states that arose in past games. VAEP also uses |
|
a more complex representation of the game state: it considers the three last |
|
actions that happened during the period: :math:`S_i = \{a_{i-2}, a_{i−1}, |
|
a_i\}`. With the code below, you can convert the SPADL action of the game to |
|
these game states: |
|
|
|
.. code-block:: python |
|
|
|
import socceraction.vaep.features as fs |
|
|
|
|
|
gamestates = fs.gamestates(actions, 3) |
|
gamestates = fs.play_left_to_right(gamestates, home_team_id) |
|
|
|
Then each game state is represented using three types of features. The first |
|
category of features includes characteristics of the action itself such as |
|
its location and type as well as more complex relationships such as the |
|
distance and angle to the goal. The second category of features captures the |
|
context of the action, such as the current tempo of the game, by comparing |
|
the properties of consecutive actions. Examples of this type of feature |
|
include the distance covered and time elapsed between consecutive actions. |
|
The third category of features captures the current game context by looking at |
|
things such as the time remaining in the match and the current score differential. |
|
The table below gives an overview the features that can be used to encoded |
|
a gamestate :math:`S_i = \{a_{i-2}, a_{i−1}, a_i\}`: |
|
|
|
+ |
|
| Transformer | Feature | Description | |
|
+====================================================+========================+==============================================================================================================================+ |
|
| :func:`~socceraction.vaep.features.actiontype` | actiontype(_onehot)_ai | The (one-hot encoding) of the action's type. | |
|
+ |
|
| :func:`~socceraction.vaep.features.result` | result(_onehot)_ai | The (one-hot encoding) of the action's result. | |
|
+ |
|
| :func:`~socceraction.vaep.features.bodypart` | actiontype(_onehot)_ai | The (one-hot encoding) of the bodypart used to perform the action. | |
|
+ |
|
| :func:`~socceraction.vaep.features.time` | time_ai | Time in the match the action takes place, recorded to the second. | |
|
+ |
|
| :func:`~socceraction.vaep.features.startlocation` | start_x_ai | The x pitch coordinate of the action's start location. | |
|
| + |
|
| | start_y_ai | The y pitch coordinate of the action's start location. | |
|
+ |
|
| :func:`~socceraction.vaep.features.endlocation` | end_x_ai | The x pitch coordinate of the action's end location. | |
|
| + |
|
| | end_y_ai | The y pitch coordinate of the action's end location. | |
|
+ |
|
| :func:`~socceraction.vaep.features.startpolar` | start_dist_to_goal_ai | The distance to the center of the goal from the action's start location. | |
|
| + |
|
| | start_angle_to_goal_ai | The angle between the action's start location and center of the goal. | |
|
+ |
|
| :func:`~socceraction.vaep.features.endpolar` | end_dist_to_goal_ai | The distance to the center of the goal from the action's end location. | |
|
| + |
|
| | end_angle_to_goal_ai | The angle between the action's end location and center of the goal. | |
|
+ |
|
| :func:`~socceraction.vaep.features.movement` | dx_ai | The distance covered by the action along the x-axis. | |
|
| + |
|
| | dy_ai | The distance covered by the action along the y-axis. | |
|
| + |
|
| | movement_ai | The total distance covered by the action. | |
|
+ |
|
| :func:`~socceraction.vaep.features.team` | team_ai | Boolean indicating whether the team that had possesion in action :math:`a_{i-2}` still has possession in the current action. | |
|
+ |
|
| :func:`~socceraction.vaep.features.time_delta` | time_delta_i | Seconds elapsed between :math:`a_{i-2}` and the current action. | |
|
+ |
|
| :func:`~socceraction.vaep.features.space_delta` | dx_a0i | The distance covered by action :math:`a_{i-2}` to :math:`a_{i}` along the x-axis. | |
|
| + |
|
| | dy_a0i | The distance covered by action :math:`a_{i-2}` to :math:`a_{i}` along the y-axis. | |
|
| + |
|
| | mov_a0i | The total distance covered by action :math:`a_{i-2}` to :math:`a_{i}`. | |
|
+ |
|
| :func:`~socceraction.vaep.features.goalscore` | goalscore_team | The number of goals scored by the team executing the action. | |
|
| + |
|
| | goalscore_opponent | The number of goals scored by the other team. | |
|
| + |
|
| | goalscore_diff | The goal difference between both teams. | |
|
+ |
|
|
|
.. code-block:: python |
|
|
|
import socceraction.vaep.features as fs |
|
|
|
|
|
xfns = [fs.actiontype, fs.result, ...] |
|
X = pd.concat([fn(gamestates) for fn in xfns], axis=1) |
|
|
|
For estimating :math:`P_{score}(S_i, t)`, each game state is given a positive |
|
label (= 1) if the team that possesses the ball after action :math:`a_i` |
|
scores a goal in the subsequent :math:`k` actions. Otherwise, a |
|
negative label (= 0) is given to the game state. Analogously, |
|
for estimating :math:`P_{concede}(S_i, t)`, each game state is given |
|
a positive label (= 1) if the team that possesses the ball after action |
|
:math:`a_i` concedes a goal in the subsequent :math:`k` actions. If not, |
|
a negative label (= 0) is given to the game state. |
|
|
|
.. code-block:: python |
|
|
|
import socceraction.vaep.labels as lab |
|
|
|
|
|
yfns = [lab.scores, lab.concedes] |
|
Y = pd.concat([fn(actions) for fn in yfns], axis=1) |
|
|
|
VAEP models the scoring and conceding probabilities separately as these |
|
effects may be asymmetric in nature and context-dependent. Hence, it trains |
|
one gradient boosted tree model to predict each one based on the current game |
|
state. |
|
|
|
|
|
.. code-block:: python |
|
|
|
|
|
models = { |
|
"scores": Classsifier(...) |
|
"concedes": Classsifier(...) |
|
} |
|
|
|
|
|
for col in ["scores", "concedes"]: |
|
Y_hat[col] = models[col].predict_proba(testX) |
|
|
|
|
|
Using these probabilities, VAEP defines the *offensive value* of an action as |
|
the change in scoring probability before and after the action. |
|
|
|
.. math:: |
|
|
|
\Delta P_\textrm{score}(a_{i}, t) = P^{k}_\textrm{score}(S_i, t) - P^{k}_\textrm{score}(S_{i-1}, t) |
|
|
|
This change |
|
will be positive if the action increased the probability that the team which |
|
performed the action will score (e.g., a successful tackle to recover the |
|
ball). Similarly, VAEP defines the *defensive value* of an action as the |
|
change in conceding probability. |
|
|
|
.. math:: |
|
|
|
\Delta P_\textrm{concede}(a_{i}, t) = P^{k}_\textrm{concede}(S_i, t) - P^{k}_\textrm{concede}(S_{i-1}, t) |
|
|
|
This change will be positive if the action |
|
increased the probability that the team will concede a goal (e.g., a failed |
|
pass). Finally, the total VAEP value of an action is the difference between |
|
that action's offensive value and defensive value. |
|
|
|
.. math:: |
|
|
|
V_\textrm{VAEP}(a_i) = \Delta P_\textrm{score}(a_{i}, t) - \Delta P_\textrm{concede}(a_{i}, t) |
|
|
|
.. code-block:: python |
|
|
|
import socceraction.vaep.formula as vaepformula |
|
|
|
|
|
values = vaepformula.value(actions, Y_hat["scores"], Y_hat["concedes"]) |
|
|
|
|
|
.. seealso:: |
|
|
|
A set of notebooks illustrates the complete pipeline to train and |
|
apply a VAEP model: |
|
|
|
1. `compute features and labels`__ |
|
2. `estimate scoring and conceding probabilities`__ |
|
3. `compute VAEP values and top players`__ |
|
|
|
__ https://github.com/ML-KULeuven/socceraction/blob/master/public-notebooks/2-compute-features-and-labels.ipynb |
|
__ https://github.com/ML-KULeuven/socceraction/blob/master/public-notebooks/3-estimate-scoring-and-conceding-probabilities.ipynb |
|
__ https://github.com/ML-KULeuven/socceraction/blob/master/public-notebooks/4-compute-vaep-values-and-top-players.ipynb |
|
|