Metadata-Version: 2.4
Name: silly-kicks
Version: 3.14.0
Summary: Classify and value on-ball football actions using SPADL and VAEP
Project-URL: Homepage, https://github.com/karsten-s-nielsen/silly-kicks
Project-URL: Repository, https://github.com/karsten-s-nielsen/silly-kicks
Author: Karsten S. Nielsen
License-Expression: MIT
License-File: LICENSE
License-File: NOTICE
Keywords: SPADL,VAEP,actions,analytics,football,soccer
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Requires-Dist: numpy>=1.26.0
Requires-Dist: pandas>=2.1.1
Requires-Dist: scikit-learn>=1.3.1
Requires-Dist: scipy>=1.10.0
Provides-Extra: catboost
Requires-Dist: catboost>=1.2; extra == 'catboost'
Provides-Extra: das
Requires-Dist: accessible-space<3,>=2.0; extra == 'das'
Provides-Extra: dev
Requires-Dist: pandas-stubs>=2.2.0; extra == 'dev'
Requires-Dist: pyright>=1.1.409; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: golden-master
Requires-Dist: unravelsports>=1.2; (python_version >= '3.11') and extra == 'golden-master'
Provides-Extra: kloppy
Requires-Dist: kloppy>=3.18.0; extra == 'kloppy'
Provides-Extra: lightgbm
Requires-Dist: lightgbm>=4.0; extra == 'lightgbm'
Provides-Extra: numba
Requires-Dist: numba>=0.59.0; extra == 'numba'
Provides-Extra: test
Requires-Dist: accessible-space<3,>=2.0; extra == 'test'
Requires-Dist: numba>=0.59.0; extra == 'test'
Requires-Dist: pyarrow>=14.0.0; extra == 'test'
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'test'
Requires-Dist: pytest-cov>=4.1.0; extra == 'test'
Requires-Dist: pytest-mock>=3.11.1; extra == 'test'
Requires-Dist: pytest>=7.4.2; extra == 'test'
Requires-Dist: tables>=3.9.0; extra == 'test'
Provides-Extra: xarray
Requires-Dist: xarray>=2024.1.0; extra == 'xarray'
Provides-Extra: xgboost
Requires-Dist: xgboost>=2.0.0; extra == 'xgboost'
Description-Content-Type: text/markdown

# Silly Kicks

![The Modern SPADL Analyst vs The Chief SPADL Evaluator & Classifier](https://raw.githubusercontent.com/karsten-s-nielsen/silly-kicks/main/assets/silly-kicks.jpg)
<sup>Comic by NanoBanana &mdash; inspired by Monty Python's <em>Ministry of Silly Walks</em></sup>

[![CI](https://github.com/karsten-s-nielsen/silly-kicks/actions/workflows/ci.yml/badge.svg)](https://github.com/karsten-s-nielsen/silly-kicks/actions/workflows/ci.yml)

*The Ministry requires that all football actions be properly classified and valued.*

**silly-kicks** is a Python library for objectively quantifying the impact of
individual actions performed by football players using event stream data.

It is an independently maintained successor to
[socceraction](https://github.com/ML-KULeuven/socceraction), originally
developed by Tom Decroos and Pieter Robberechts at KU Leuven. Built under the
MIT license with full attribution preserved.

## Features

- **SPADL** -- Soccer Player Action Description Language: a unified schema for
  on-ball actions with dedicated DataFrame converters for StatsBomb, Wyscout,
  Opta, Sportec / IDSSE Bundesliga, Metrica Sports, and Gradient Sports — plus a kloppy
  gateway for raw-provider-data consumers (StatsBomb, Sportec, Metrica)
- **Tracking** -- 20-column long-form per-frame schema parallel to SPADL, with
  native adapters for Sportec / IDSSE Bundesliga and Gradient Sports plus a kloppy
  gateway for Metrica + SkillCorner. Key capabilities: action-to-frame linkage,
  frame preprocessing (smoothing, interpolation, velocities), GK identification,
  defensive-line geometry, ball-carrier inference, and 40+ tracking-aware
  action-context features for HybridVAEP integration including pitch control
  (Spearman / Fernández-Bornn / Voronoi), GK influence primitives (GKDV
  Layer 1), pressure (three published methods), pre-shot GK position/angles,
  pre-action movement, off-ball runs, line-break detection (threshold + Ward
  clustering), and team shape envelope. Full feature inventory in the
  [CHANGELOG](CHANGELOG.md).
- **VAEP** -- Valuing Actions by Estimating Probabilities: a framework for
  quantifying the value of individual actions
- **Atomic SPADL** -- continuous (non-discretized) action representation

## Installation

```bash
pip install silly-kicks
```

Requires Python 3.10 or later.

With optional provider support:

```bash
pip install "silly-kicks[kloppy,xgboost]"
```

## Quick Start

```python
import silly_kicks.spadl as spadl

# Convert StatsBomb events to SPADL actions
actions, report = spadl.statsbomb.convert_to_actions(events, home_team_id=123)

# Add human-readable names
actions = spadl.add_names(actions)
```

## VAEP Workflow

The full pipeline: convert provider events to SPADL, train a VAEP model, and
rate individual actions.

```python
from silly_kicks.spadl import statsbomb
from silly_kicks.vaep import VAEP

# 1. Convert provider events to SPADL
actions, report = statsbomb.convert_to_actions(
    events_df, home_team_id=home_team_id,
    xy_fidelity_version=2, shot_fidelity_version=2,
)

# 2. Train a VAEP model
model = VAEP(nb_prev_actions=3)
features = model.compute_features(game, actions)
labels = model.compute_labels(game, actions)
model.fit(features, labels, learner="xgboost", random_state=42)

# 3. Rate actions
ratings = model.rate(game, actions)
# Returns DataFrame with offensive_value, defensive_value, vaep_value
```

### Hybrid-VAEP

Standard VAEP includes the action's result (success/fail) as a feature, which
creates information leakage. HybridVAEP removes result information from the
current action while preserving it for previous actions.

```python
from silly_kicks.vaep import HybridVAEP

# HybridVAEP removes result leakage from current-action features
model = HybridVAEP(nb_prev_actions=3)
# Same fit/rate API as standard VAEP
```

### Multi-Provider Support

All converters share the same output schema, so downstream code works
identically regardless of the data provider.

```python
from silly_kicks.spadl import opta, wyscout

actions_opta, _ = opta.convert_to_actions(opta_events, home_team_id)
actions_wyscout, _ = wyscout.convert_to_actions(wyscout_events, home_team_id)
```

## Architecture

Open [`docs/c4/architecture.html`](docs/c4/architecture.html) in a browser to explore the C4 architecture diagrams (System Context, Containers).

## Attribution

This project incorporates academic methodologies from the soccer-analytics
literature. See [NOTICE](NOTICE) for full bibliographic citations and
third-party library acknowledgements.

silly-kicks builds on the foundational research by the KU Leuven Machine
Learning Research Group. If you use this library in academic work, please cite
the original papers:

```bibtex
@inproceedings{Decroos2019VAEP,
  title     = {Actions Speak Louder than Goals: Valuing Player Actions in Soccer},
  author    = {Tom Decroos and Lotte Bransen and Jan Van Haaren and Jesse Davis},
  booktitle = {Proceedings of the 25th ACM SIGKDD International Conference
               on Knowledge Discovery \& Data Mining},
  pages     = {1851--1861},
  year      = {2019},
  doi       = {10.1145/3292500.3330758}
}

@inproceedings{Decroos2020AtomicSPADL,
  title     = {Interpretable Prediction of Goals in Soccer},
  author    = {Tom Decroos and Jesse Davis},
  booktitle = {Proceedings of the AAAI-20 Workshop on Artificial Intelligence
               in Team Sports},
  year      = {2020}
}
```

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding standards,
and PR process. Open items and planned work are tracked in [TODO.md](TODO.md).

## License

MIT License. See [LICENSE](LICENSE) for details.
