TL;DR
- Deprecated `SoccerGraphConverter` in favor of `SoccerGraphConverterPolars`. This will be removed in the future.
- note: This currently means the Graph features are slightly different and thus `SoccerGraphConverter` models are not compatible with `SoccerGraphConverterPolars`
- note: This means, for the time being, we have _node_features_pl.py_, _edge_features_pl.py_ and _adjacency_matrix_pl.py_ alongside the non-_polars_ ones.
- Introduced `unravel.soccer.PressingIntensity`, see [**Pressing Intensity Jupyter Notebook**](https://github.com/UnravelSports/unravelsports/blob/main/examples/pressing_intensity.ipynb) for an example!
- Removed necessity for Polars datasets to `.load()`. This is now called within `__init__`.
- Introduced settings dataclass into Polars datasets (`BigDataBowlDataset` and `KloppyPolarsDataset`).
- For now we keep `SoccerGraphConverter` as separate functionality, with a deprecation warning to move to `SoccerGraphConverterPolars`
- Additionally aligned `AmericanFootballGraphConverter` (which already had a Polars backend) with syntax used in `SoccerGraphConverterPolars`
------
Change Log
KloppyPolarsDataset
We introduce a `KloppyPolarsDataset` that converts the `kloppy_dataset` to a Polars dataframe and does a number of conversions and checks. Use it as follows:
python
kloppy_dataset = sportec.load_open_tracking_data(
match_id=match_id,
coordinates="secondspectrum",
only_alive=True,
limit=500, limit to 500 frames in this example
)
kloppy_polars_dataset = KloppyPolarsDataset(
kloppy_dataset=kloppy_dataset,
ball_carrier_threshold=25.0,
max_ball_speed=28.0,
max_player_speed=12.0,
max_player_acceleration=6.0,
max_ball_acceleration=13.5,
orient_ball_owning=True
)
This is where you add your own training labels
kloppy_polars_dataset.add_dummy_labels()
kloppy_polars_dataset.add_graph_ids()
- `ball_carrier_threshold`, `max_ball_speed`, `max_player_speed`, `max_ball_acceleration` and `max_player_acceleration` have been moved to `KloppyPolarsDataset`
- `KloppyPolarsDataset` sets the orientation to `Orientation.BALL_OWNING_TEAM` (ball owning team plays left to right) when `orient_ball_owning=True`. If our dataset does not have the ball owning team we infer the ball owning team automatically using the `ball_carrier_threshold` and subsequently change the orientation automatically to be left to right for the ball owning team too. Additionally, we automatically identify the ball carrying player as the player on the ball owning team closest to the ball.
- Fixed `Orientation.BALL_OWNING_TEAM` messing up our velocity and acceleration calculations.
Note: In `SoccerGraphConverter` if the ball owning team was not available we set the orientation to STATIC_HOME_AWAY meaning attacking could happen in two directions. I felt this was undesirable.
-----
SoccerGraphConverterPolars
- `boundary_correction` has been removed as a parameter
- `infer_ball_ownership` has been removed as a parameter, this is now always handled automatically when necessary
- `infer_goalkeepers` has been removed as a parameter, this is now always handled automatically when necessary. If we have position labels (e.g. "GK") we use that.
- `labels`, `graph_id`, `graph_ids` have been removed as parameters. We can now use `label_col` and `graph_id_col` as parameters, they default to "label" and "graph_id".
python
from unravel.soccer import SoccerGraphConverterPolars, KloppyPolarsDataset
from unravel.utils import CustomSpektralDataset
from kloppy import sportec
Load Kloppy dataset
kloppy_dataset = sportec.load_open_tracking_data(only_alive=True, limit=500)
kloppy_polars_dataset = KloppyPolarsDataset(
kloppy_dataset=kloppy_dataset,
)
kloppy_polars_dataset.add_dummy_labels()
kloppy_polars_dataset.add_graph_ids(by=["frame_id"])
Initialize the Graph Converter with dataset
Here we use the default settings
converter = SoccerGraphConverterPolars(dataset=kloppy_polars_dataset)
Compute the graphs and add them to the CustomSpektralDataset
dataset = CustomSpektralDataset(graphs=converter.to_spektral_graphs())
------
Pressing Intensity
See [**Pressing Intensity Jupyter Notebook**](https://github.com/UnravelSports/unravelsports/blob/main/examples/pressing_intensity.ipynb) for an example!
python
from unravel.soccer import PressingIntensity
import polars as pl
model = PressingIntensity(dataset=kloppy_polars_dataset)
model.fit(
start_time=pl.duration(minutes=1, seconds=53),
end_time=pl.duration(minutes=2, seconds=32),
period_id=1,
method="teams",
ball_method="max",
orient="home_away",
speed_threshold=2.0,
)
model.output.head()
------
Settings
- Introduced `settings` dataclass into Polars datasets (`BigDataBowlDataset` and `KloppyPolarsDataset`). Available through `dataset.settings`.
python
class DefaultSettings:
home_team_id: Union[str, int]
away_team_id: Union[str, int]
provider: Union[Provider, str]
pitch_dimensions: Union[MetricPitchDimensions, AmericanFootballPitchDimensions]
orientation: Orientation
max_player_speed: float = 12.0
max_ball_speed: float = 28.0
max_player_acceleration: float = 6.0
max_ball_acceleration: float = 13.5
ball_carrier_threshold: float = 25.0
------
Backend
- Introduced `Constant`, `Column` and `Group` dataclasses to more easily track which columns we are using under the hood.
python
class Constant:
BALL = "ball"
class Column:
BALL_OWNING_TEAM_ID = "ball_owning_team_id"
....
class Group:
BY_FRAME = [Column.GAME_ID, Column.PERIOD_ID, Column.FRAME_ID]
....
- Updated examples
- Updated tests