| | import os |
| |
|
| | import pandas as pd |
| | from socceraction.data.wyscout import PublicWyscoutLoader |
| | from socceraction.spadl import SPADLSchema |
| | from socceraction.spadl import config as spadl |
| | from socceraction.spadl import wyscout as wy |
| |
|
| |
|
| | class TestSpadlConvertor: |
| | def setup_method(self) -> None: |
| | data_dir = os.path.join( |
| | os.path.dirname(__file__), os.pardir, "datasets", "wyscout_public", "raw" |
| | ) |
| | self.WSL = PublicWyscoutLoader(root=data_dir, download=False) |
| | self.events = self.WSL.events(2058007) |
| |
|
| | def test_convert_to_actions(self) -> None: |
| | df_actions = wy.convert_to_actions(self.events, 5629) |
| | assert len(df_actions) > 0 |
| | SPADLSchema.validate(df_actions) |
| | assert (df_actions.game_id == 2058007).all() |
| | assert ((df_actions.team_id == 5629) | (df_actions.team_id == 12913)).all() |
| |
|
| | def test_insert_interception_passes(self) -> None: |
| | event = pd.DataFrame( |
| | [ |
| | { |
| | "type_id": 8, |
| | "subtype_name": "Head pass", |
| | "tags": [{"id": 102}, {"id": 1401}, {"id": 1801}], |
| | "player_id": 38093, |
| | "positions": [{"y": 56, "x": 5}, {"y": 100, "x": 100}], |
| | "game_id": 2499737, |
| | "type_name": "Pass", |
| | "team_id": 1610, |
| | "period_id": 2, |
| | "milliseconds": 2184.793924, |
| | "subtype_id": 82, |
| | "event_id": 180427412, |
| | } |
| | ] |
| | ) |
| | actions = wy.convert_to_actions(event, 1610) |
| | assert len(actions) == 2 |
| | assert actions.at[0, "type_id"] == spadl.actiontypes.index("interception") |
| | assert actions.at[1, "type_id"] == spadl.actiontypes.index("bad_touch") |
| | assert actions.at[0, "result_id"] == spadl.results.index("success") |
| | assert actions.at[1, "result_id"] == spadl.results.index("owngoal") |
| |
|
| | def test_convert_own_goal(self) -> None: |
| | events_morira = self.WSL.events(2057961) |
| | own_goal_event = events_morira[events_morira.event_id == 258696133] |
| | own_goal_actions = wy.convert_to_actions(own_goal_event, 16216) |
| | assert len(own_goal_actions) == 2 |
| | assert own_goal_actions.iloc[0]["type_id"] == spadl.actiontypes.index("interception") |
| | assert own_goal_actions.iloc[0]["result_id"] == spadl.results.index("success") |
| | assert own_goal_actions.iloc[1]["type_id"] == spadl.actiontypes.index("bad_touch") |
| | assert own_goal_actions.iloc[1]["result_id"] == spadl.results.index("owngoal") |
| | assert own_goal_actions.iloc[1]["bodypart_id"] == spadl.bodyparts.index("foot") |
| |
|
| | def test_convert_own_goal_touches(self) -> None: |
| | """Tests conversion of own goals following a bad touch. |
| | |
| | Own goals resulting from bad touch events in the Wyscout event |
| | streams should be included in the SPADL representation. |
| | """ |
| | |
| | |
| | |
| | event = pd.DataFrame( |
| | [ |
| | { |
| | "type_id": 8, |
| | "subtype_name": "Cross", |
| | "tags": [{"id": 402}, {"id": 801}, {"id": 1802}], |
| | "player_id": 8013, |
| | "positions": [{"y": 89, "x": 97}, {"y": 0, "x": 0}], |
| | "game_id": 2499994, |
| | "type_name": "Pass", |
| | "team_id": 1631, |
| | "period_id": 2, |
| | "milliseconds": 1496.7290489999993, |
| | "subtype_id": 80, |
| | "event_id": 230320305, |
| | }, |
| | { |
| | "type_id": 7, |
| | "subtype_name": "Touch", |
| | "tags": [{"id": 102}], |
| | "player_id": 8094, |
| | "positions": [{"y": 50, "x": 1}, {"y": 100, "x": 100}], |
| | "game_id": 2499994, |
| | "type_name": "Others on the ball", |
| | "team_id": 1639, |
| | "period_id": 2, |
| | "milliseconds": 1497.6330749999993, |
| | "subtype_id": 72, |
| | "event_id": 230320132, |
| | }, |
| | { |
| | "type_id": 9, |
| | "subtype_name": "Reflexes", |
| | "tags": [{"id": 101}, {"id": 1802}], |
| | "player_id": 8094, |
| | "positions": [{"y": 100, "x": 100}, {"y": 50, "x": 1}], |
| | "game_id": 2499994, |
| | "type_name": "Save attempt", |
| | "team_id": 1639, |
| | "period_id": 2, |
| | "milliseconds": 1499.980547, |
| | "subtype_id": 90, |
| | "event_id": 230320135, |
| | }, |
| | ] |
| | ) |
| | actions = wy.convert_to_actions(event, 1639) |
| | |
| | |
| | |
| | assert len(actions) == 4 |
| | assert actions.at[1, "type_id"] == spadl.actiontypes.index("bad_touch") |
| | assert actions.at[1, "result_id"] == spadl.results.index("owngoal") |
| |
|
| | def test_convert_simulations_precede_by_take_on(self) -> None: |
| | events = pd.DataFrame( |
| | [ |
| | { |
| | "type_id": 1, |
| | "subtype_name": "Ground attacking duel", |
| | "tags": [{"id": 503}, {"id": 701}, {"id": 1802}], |
| | "player_id": 8327, |
| | "positions": [{"y": 48, "x": 82}, {"y": 47, "x": 83}], |
| | "game_id": 2576263, |
| | "type_name": "Duel", |
| | "team_id": 3158, |
| | "period_id": 2, |
| | "milliseconds": 706.309475 * 1000, |
| | "subtype_id": 11, |
| | "event_id": 240828365, |
| | }, |
| | { |
| | "type_id": 2, |
| | "subtype_name": "Simulation", |
| | "tags": [{"id": 1702}], |
| | "player_id": 8327, |
| | "positions": [{"y": 47, "x": 83}, {"y": 0, "x": 0}], |
| | "game_id": 2576263, |
| | "type_name": "Foul", |
| | "team_id": 3158, |
| | "period_id": 2, |
| | "milliseconds": 709.1020480000002 * 1000, |
| | "subtype_id": 25, |
| | "event_id": 240828368, |
| | }, |
| | ] |
| | ) |
| |
|
| | actions = wy.convert_to_actions(events, 3158) |
| |
|
| | assert len(actions) == 1 |
| | assert actions.at[0, "type_id"] == spadl.actiontypes.index("take_on") |
| | assert actions.at[0, "result_id"] == spadl.results.index("fail") |
| |
|
| | def test_convert_simulations(self) -> None: |
| | events = pd.DataFrame( |
| | [ |
| | { |
| | "type_id": 8, |
| | "subtype_name": "Cross", |
| | "tags": [{"id": 402}, {"id": 801}, {"id": 1801}], |
| | "player_id": 20472, |
| | "positions": [{"y": 76, "x": 92}, {"y": 92, "x": 98}], |
| | "game_id": 2575974, |
| | "type_name": "Pass", |
| | "team_id": 3173, |
| | "period_id": 1, |
| | "milliseconds": 1010.5460250000001 * 1000, |
| | "subtype_id": 80, |
| | "event_id": 182640540, |
| | }, |
| | { |
| | "type_id": 1, |
| | "subtype_name": "Ground loose ball duel", |
| | "tags": [{"id": 701}, {"id": 1802}], |
| | "player_id": 116171, |
| | "positions": [{"y": 92, "x": 98}, {"y": 43, "x": 87}], |
| | "game_id": 2575974, |
| | "type_name": "Duel", |
| | "team_id": 3173, |
| | "period_id": 1, |
| | "milliseconds": 1012.8018770000001 * 1000, |
| | "subtype_id": 13, |
| | "event_id": 182640541, |
| | }, |
| | { |
| | "type_id": 2, |
| | "subtype_name": "Simulation", |
| | "tags": [{"id": 1702}], |
| | "player_id": 116171, |
| | "positions": [{"y": 43, "x": 87}, {"y": 100, "x": 100}], |
| | "game_id": 2575974, |
| | "type_name": "Foul", |
| | "team_id": 3173, |
| | "period_id": 1, |
| | "milliseconds": 1014.7540220000001 * 1000, |
| | "subtype_id": 25, |
| | "event_id": 182640542, |
| | }, |
| | ] |
| | ) |
| |
|
| | actions = wy.convert_to_actions(events, 3157) |
| |
|
| | assert len(actions) == 3 |
| | assert actions.at[2, "type_id"] == spadl.actiontypes.index("take_on") |
| | assert actions.at[2, "result_id"] == spadl.results.index("fail") |
| |
|