Skip to content

Commit

Permalink
add opta blocked pass as interception and for wyscout-v2 touch and du…
Browse files Browse the repository at this point in the history
…el as interception.
  • Loading branch information
MKlaasman committed Nov 14, 2023
1 parent 471da05 commit bdc6d33
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 17 deletions.
21 changes: 12 additions & 9 deletions kloppy/infra/serializers/event/opta/deserializer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Tuple, Dict, List, NamedTuple, IO
from typing import Tuple, Dict, List, NamedTuple, IO, Optional
import logging
from datetime import datetime
import pytz
Expand Down Expand Up @@ -78,6 +78,7 @@
EVENT_TYPE_RECOVERY = 49
EVENT_TYPE_FORMATION_CHANGE = 40
EVENT_TYPE_BALL_TOUCH = 61
EVENT_TYPE_BLOCKED_PASS = 74

EVENT_TYPE_SAVE = 10
EVENT_TYPE_CLAIM = 11
Expand Down Expand Up @@ -391,7 +392,7 @@ def _parse_interception(
qualifiers = _get_event_qualifiers(raw_qualifiers)
result = InterceptionResult.SUCCESS

if next_event:
if next_event is not None:
next_event_type_id = int(next_event.attrib["type_id"])
if next_event_type_id in BALL_OUT_EVENTS:
result = InterceptionResult.OUT
Expand Down Expand Up @@ -642,7 +643,11 @@ def deserialize(self, inputs: OptaInputs) -> EventDataset:
]
possession_team = None
events = []
events_list = list(game_elm.iterchildren("Event"))
events_list = [
event
for event in list(game_elm.iterchildren("Event"))
if int(event.attrib["type_id"]) != EVENT_TYPE_DELETED_EVENT
]
for idx, event_elm in enumerate(events_list):
next_event_elm = (
events_list[idx + 1]
Expand Down Expand Up @@ -672,11 +677,6 @@ def deserialize(self, inputs: OptaInputs) -> EventDataset:
f"Set end of period {period.id} to {timestamp}"
)
period.end_timestamp = timestamp
elif type_id == EVENT_TYPE_DELETED_EVENT:
logger.debug(
f"Skipping event {event_id} because it is a deleted event (type id - {type_id})"
)
continue
else:
if not period.start_timestamp:
# not started yet
Expand Down Expand Up @@ -792,7 +792,10 @@ def deserialize(self, inputs: OptaInputs) -> EventDataset:
**duel_event_kwargs,
**generic_event_kwargs,
)
elif type_id == EVENT_TYPE_INTERCEPTION:
elif type_id in (
EVENT_TYPE_INTERCEPTION,
EVENT_TYPE_BLOCKED_PASS,
):
interception_event_kwargs = _parse_interception(
raw_qualifiers, team, next_event_elm
)
Expand Down
14 changes: 9 additions & 5 deletions kloppy/infra/serializers/event/wyscout/deserializer_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,8 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset:
**generic_event_args,
)

# If also an interception event, add this before other event (It is a tag on multiple wyscout_events)
# Since Interception is not an event in wyscout v2 but a tag for pass, touch and duel. Therefore,
# we convert those duels and touch events to an interception. And insert interception before passes.
if _has_tag(raw_event, wyscout_tags.INTERCEPTION):
interception_event_args = _parse_interception(
raw_event, next_event
Expand All @@ -520,13 +521,16 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset:
**generic_event_args,
)

if event.event_type.name != "RECOVERY":
if event.event_type.name == "DUEL":
# when DuelEvent is interception, we need to overwrite this and the previous DuelEvent
events = events[:-1]
event = interception_event
elif event.event_name in ["recovery", "miscontrol"]:
event = interception_event
elif event.event_name in ["pass", "clearance"]:
events.append(
transformer.transform_event(interception_event)
)
else:
# overwrite recovery event
event = interception_event

if event and self.should_include_event(event):
events.append(transformer.transform_event(event))
Expand Down
6 changes: 3 additions & 3 deletions kloppy/tests/test_wyscout.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def test_correct_v2_deserialization(self, event_v2_data: Path):
assert dataset.records[2].coordinates == Point(29.0, 6.0)
assert dataset.events[11].event_type == EventType.MISCONTROL
assert dataset.events[34].event_type == EventType.INTERCEPTION
assert dataset.events[144].event_type == EventType.CLEARANCE
assert dataset.events[143].event_type == EventType.CLEARANCE

assert (
dataset.events[39].get_qualifier_value(DuelQualifier)
Expand All @@ -81,11 +81,11 @@ def test_correct_v2_deserialization(self, event_v2_data: Path):
== DuelType.AERIAL
)
assert (
dataset.events[269].get_qualifier_values(DuelQualifier)[2].value
dataset.events[268].get_qualifier_values(DuelQualifier)[2].value
== DuelType.SLIDING_TACKLE
)
assert (
dataset.events[302].get_qualifier_value(GoalkeeperQualifier)
dataset.events[301].get_qualifier_value(GoalkeeperQualifier)
== GoalkeeperActionType.SAVE
)

Expand Down

0 comments on commit bdc6d33

Please sign in to comment.