PySport / kloppy

kloppy: standardizing soccer tracking- and event data
https://kloppy.pysport.org
BSD 3-Clause "New" or "Revised" License
362 stars 59 forks source link

Store the formation changes of a team in Team object #301

Open DriesDeprest opened 6 months ago

DriesDeprest commented 6 months ago

I would like to create a formation_changes attribute in our Team class. I would use it to make it easier to calculate how much a team has played in a given formation in downstream usage of the EventsDataset.

My proposal would be to make a similar change as we are planning to do for player positions, where we are moving from having a (starting) position attribute to a position_changes attribute, with a starting_position and position method to easily retrieve the position at any given moment. The details of these changes are discussed in: https://github.com/PySport/kloppy/issues/277.

So the changes to our Team class, would look something like this:

@dataclass(frozen=True)
class FormationChange:
    timestamp: timedelta
    period_id: int
    formation: Formation

@dataclass
class Team:
    team_id: str
    name: str
    ground: Ground
    formation_changes: List[FormationChange] = field(default_factory=list)
    players: List[Player] = field(default_factory=list)

    @property
    def starting_formation(self):
        if self.formation_changes:
            return self.formation_changes[0].formation

    def formation(self, period_id: int, timestamp: timedelta):
        if self.formation_changes:
            formation = self.formation_changes[0].formation
            for formation_change in self.formation_changes:
                # Check if the current change is before or exactly at the given period and timestamp
                if period_id > formation_change.period_id or (
                    period_id == formation_change.period_id
                    and timestamp >= formation_change.timestamp
                ):
                    formation = formation_change.position
                else:
                    # Since the list is assumed to be in chronological order, break on finding the first future change
                    break

            return formation

However, I am bit struggling with how to think about the overlap of functionality between the add_state method with 'formation' argument and the new formation method. They seem to be both serving a similar functionality, determining the formation of team at a given timepoint in the game. Maybe, their purposes are slightly different and it is deseriable to have the both of them in kloppy?

@probberechts @JanVanHaaren @koenvo thoughts?