Skip to content

Commit

Permalink
refactored databallpy_events (#236)
Browse files Browse the repository at this point in the history
* refactored databallpy_events

* updated version debugpy

* Updated docs
  • Loading branch information
Alek050 authored Aug 6, 2024
1 parent 0a16c3b commit 6103cdf
Show file tree
Hide file tree
Showing 27 changed files with 2,140 additions and 1,872 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -347,19 +347,17 @@ def _get_shot_event(
start_x=row.start_x,
start_y=row.start_y,
team_id=row.team_id,
pitch_size=pitch_dimensions,
team_side="home" if row.team_id == home_team_id else "away",
_xt=-1.0,
pitch_size=pitch_dimensions,
player_id=row.player_id,
jersey=players.loc[players["id"] == row.player_id, "shirt_num"].iloc[0],
shot_outcome=["miss", "goal"][row.outcome],
y_target=np.nan,
z_target=np.nan,
body_part=None,
type_of_play=None,
first_touch=None,
created_oppertunity=None,
outcome=bool(row.outcome),
related_event_id=MISSING_INT,
body_part="unspecified",
possession_type="unspecified",
set_piece="unspecified",
_xt=np.nan,
outcome_str=["miss", "goal"][row.outcome],
)


Expand Down Expand Up @@ -390,18 +388,22 @@ def _get_pass_event(
start_x=row.start_x,
start_y=row.start_y,
team_id=row.team_id,
pitch_size=pitch_dimensions,
team_side="home" if row.team_id == home_team_id else "away",
_xt=-1.0,
pitch_size=pitch_dimensions,
player_id=row.player_id,
jersey=players.loc[players["id"] == row.player_id, "shirt_num"].iloc[0],
outcome=["unsuccessful", "successful"][row.outcome]
outcome=bool(row.outcome),
related_event_id=MISSING_INT,
body_part="unspecified",
possession_type="unspecified",
set_piece="unspecified",
_xt=np.nan,
outcome_str=["unsuccessful", "successful"][row.outcome]
if not pd.isnull(row.outcome)
else "not_specified",
end_x=row.end_x,
end_y=row.end_y,
pass_type="not_specified",
set_piece="unspecified_set_piece",
pass_type="unspecified",
)


Expand Down Expand Up @@ -432,13 +434,16 @@ def _get_dribble_event(
start_x=row.start_x,
start_y=row.start_y,
team_id=row.team_id,
pitch_size=pitch_dimensions,
team_side="home" if row.team_id == home_team_id else "away",
_xt=-1.0,
pitch_size=pitch_dimensions,
player_id=row.player_id,
jersey=players.loc[players["id"] == row.player_id, "shirt_num"].iloc[0],
related_event_id=MISSING_INT,
duel_type=None,
outcome=bool(row.outcome),
has_opponent=False,
related_event_id=MISSING_INT,
body_part="unspecified",
possession_type="unspecified",
set_piece="unspecified",
_xt=np.nan,
duel_type="unspecified",
with_opponent=False,
)
105 changes: 57 additions & 48 deletions databallpy/data_parsers/event_data_parsers/opta_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
from pandas._libs.tslibs.timestamps import Timestamp

from databallpy.data_parsers import Metadata
from databallpy.events import BaseOnBallEvent, DribbleEvent, PassEvent, ShotEvent
from databallpy.events import (
DribbleEvent,
IndividualCloseToBallEvent,
PassEvent,
ShotEvent,
)
from databallpy.utils.constants import MISSING_INT
from databallpy.utils.logging import create_logger
from databallpy.utils.tz_modification import convert_datetime, utc_to_local_datetime
Expand Down Expand Up @@ -109,9 +114,9 @@

SHOT_ORIGINS_QUALIFIERS = {
9: "penalty",
22: "regular_play",
22: "open_play",
23: "counter_attack",
24: "crossed_free_kick",
24: "free_kick",
25: "corner_kick",
26: "free_kick",
}
Expand Down Expand Up @@ -176,7 +181,9 @@

def load_opta_event_data(
f7_loc: str, f24_loc: str, pitch_dimensions: list = [106.0, 68.0]
) -> tuple[pd.DataFrame, Metadata, dict[str, dict[str, dict[str, BaseOnBallEvent]]]]:
) -> tuple[
pd.DataFrame, Metadata, dict[str, dict[str, dict[str, IndividualCloseToBallEvent]]]
]:
"""This function retrieves the metadata and event data of a specific match. The x
and y coordinates provided have been scaled to the dimensions of the pitch, with
(0, 0) being the center. Additionally, the coordinates have been standardized so
Expand Down Expand Up @@ -462,7 +469,7 @@ def _load_event_data(
away_team_id: int,
players: pd.DataFrame,
pitch_dimensions: list = [106.0, 68.0],
) -> tuple[pd.DataFrame, dict[str, dict[str | int, BaseOnBallEvent]]]:
) -> tuple[pd.DataFrame, dict[str, dict[str | int, IndividualCloseToBallEvent]]]:
"""Function to load the f27 .xml, the events of the match.
Note: this function does ignore most qualifiers for now.
Expand All @@ -478,7 +485,7 @@ def _load_event_data(
Returns:
pd.DataFrame: all events of the match in a pd dataframe
dict: dict with "shot_events", "dribble_events", and "pass_events"
as key and a dict with the BaseOnBallEvent instances
as key and a dict with the BaseIndividualCloseToBallEvent instances
"""

dribble_events = {}
Expand Down Expand Up @@ -639,7 +646,7 @@ def _make_pass_instance(
pass_type_list = [
PASS_TYPE_QUALIFIERS[q] for q in qualifier_ids if q in PASS_TYPE_QUALIFIERS
]
pass_type = pass_type_list[0] if len(pass_type_list) > 0 else "not_specified"
pass_type = pass_type_list[0] if len(pass_type_list) > 0 else "unspecified"
pass_type_hiearchy = ["cross", "through_ball", "long_ball"]
for pass_type_option in pass_type_hiearchy:
if pass_type_option in pass_type_list:
Expand Down Expand Up @@ -686,19 +693,23 @@ def _make_pass_instance(
datetime=_get_valid_opta_datetime(event),
start_x=x_start,
start_y=y_start,
pitch_size=pitch_dimensions,
team_side="home" if int(event.attrs["team_id"]) != away_team_id else "away",
_xt=-1.0,
outcome=outcome,
team_id=int(event.attrs["team_id"]),
team_side="home" if int(event.attrs["team_id"]) != away_team_id else "away",
pitch_size=pitch_dimensions,
player_id=int(event.attrs["player_id"]),
jersey=players.loc[
players["id"] == int(event.attrs["player_id"]), "shirt_num"
].iloc[0],
outcome=bool(event.attrs["outcome"]),
related_event_id=MISSING_INT,
body_part="unspecified",
possession_type="unspecified",
set_piece=set_piece,
_xt=-1.0,
outcome_str=outcome,
end_x=x_end,
end_y=y_end,
pass_type=pass_type,
set_piece=set_piece,
)


Expand Down Expand Up @@ -758,9 +769,7 @@ def _make_shot_event_instance(
for q in qualifiers
if int(q["qualifier_id"]) in SHOT_ORIGINS_QUALIFIERS
]
type_of_play = (
type_of_play_list[0] if len(type_of_play_list) > 0 else "regular_play"
)
type_of_play = type_of_play_list[0] if len(type_of_play_list) > 0 else "open_play"

body_part_list = [
BODY_PART_QUALIFIERS[int(q["qualifier_id"])]
Expand All @@ -778,53 +787,50 @@ def _make_shot_event_instance(
first_touch = (
event.find("Q", {"qualifier_id": str(FIRST_TOUCH_QUALIFIER)}) is not None
)

created_oppertunity_list = [
int(q["qualifier_id"])
for q in qualifiers
if int(q["qualifier_id"]) in CREATED_OPPERTUNITY_QUALIFIERS
]
created_oppertunity = (
CREATED_OPPERTUNITY_QUALIFIERS[created_oppertunity_list[0]]
if len(created_oppertunity_list) > 0
else "regular_play"
)

if event.find("Q", {"qualifier_id": str(RELATED_EVENT_QUALIFIER)}) is not None:
related_event_id = int(
event.find("Q", {"qualifier_id": str(RELATED_EVENT_QUALIFIER)})["value"]
)
else:
related_event_id = MISSING_INT

# set piece
set_piece_list = [
SET_PIECE_QUALIFIERS[int(q["qualifier_id"])]
for q in qualifiers
if int(q["qualifier_id"]) in SET_PIECE_QUALIFIERS
]
set_piece = set_piece_list[0] if len(set_piece_list) > 0 else "no_set_piece"

if int(event.attrs["team_id"]) == away_team_id:
x_start *= -1
y_start *= -1

return ShotEvent(
player_id=int(event.attrs["player_id"]),
jersey=players.loc[
players["id"] == int(event.attrs["player_id"]), "shirt_num"
].iloc[0],
event_id=int(event.attrs["id"]),
period_id=int(event.attrs["period_id"]),
minutes=int(event.attrs["min"]),
seconds=int(event.attrs["sec"]),
datetime=_get_valid_opta_datetime(event),
start_x=x_start,
start_y=y_start,
_xt=-1.0,
pitch_size=pitch_dimensions,
team_side="home" if int(event.attrs["team_id"]) != away_team_id else "away",
team_id=int(event.attrs["team_id"]),
shot_outcome=shot_outcome,
pitch_size=pitch_dimensions,
player_id=int(event.attrs["player_id"]),
jersey=players.loc[
players["id"] == int(event.attrs["player_id"]), "shirt_num"
].iloc[0],
outcome=shot_outcome == "goal",
related_event_id=related_event_id,
body_part=body_part,
possession_type=type_of_play,
set_piece=set_piece,
_xt=-1.0,
outcome_str=shot_outcome,
y_target=y_target,
z_target=z_target,
body_part=body_part,
type_of_play=type_of_play,
first_touch=first_touch,
created_oppertunity=created_oppertunity,
related_event_id=related_event_id,
)


Expand Down Expand Up @@ -873,25 +879,28 @@ def _make_dribble_event_instance(
y_start *= -1

dribble_event = DribbleEvent(
player_id=int(event.attrs["player_id"]),
jersey=players.loc[
players["id"] == int(event.attrs["player_id"]), "shirt_num"
].iloc[0],
event_id=int(event.attrs["id"]),
period_id=int(event.attrs["period_id"]),
minutes=int(event.attrs["min"]),
seconds=int(event.attrs["sec"]),
datetime=_get_valid_opta_datetime(event),
start_x=x_start,
start_y=y_start,
pitch_size=pitch_dimensions,
_xt=-1.0,
team_side="home" if int(event.attrs["team_id"]) != away_team_id else "away",
team_id=int(event.attrs["team_id"]),
team_side="home" if int(event.attrs["team_id"]) != away_team_id else "away",
pitch_size=pitch_dimensions,
player_id=int(event.attrs["player_id"]),
jersey=players.loc[
players["id"] == int(event.attrs["player_id"]), "shirt_num"
].iloc[0],
outcome=bool(event.attrs["outcome"]),
related_event_id=related_event_id,
body_part="foot",
possession_type="unspecified",
set_piece="no_set_piece",
_xt=-1.0,
duel_type=duel_type,
outcome=bool(event.attrs["outcome"]),
has_opponent=True, # opta take ons are always against an opponent
with_opponent=True, # opta take ons are always against an opponent
)

return dribble_event
Expand Down Expand Up @@ -987,6 +996,6 @@ def _update_pass_outcome(
else:
related_pass = related_pass.iloc[0]
# assign assist to pass
pass_events[related_pass["event_id"]].outcome = "assist"
pass_events[related_pass["event_id"]].outcome_str = "assist"

return pass_events
Loading

0 comments on commit 6103cdf

Please sign in to comment.