A Python library for calculating Tactical Versatility Index (TVI) in football analytics
Project description
TVI Football Index
A Python library for calculating the Tactical Versatility Index (TVI), a metric that quantifies a player's ability to perform various actions across different zones of the football pitch. TVI measures how versatile a player is by analyzing their action diversity and spatial coverage.
What is TVI?
The Tactical Versatility Index measures player versatility by:
- Action Diversity: How many different types of actions a player performs
- Spatial Coverage: How many different pitch zones a player is active in
- Time Normalization: Adjusting for actual playing time
Higher TVI scores indicate more versatile players who contribute across multiple areas and action types. The contribution of each action can be optionally weighted by action rarity (quantiles), giving higher weights to the "action diversity" score for players that perform less common actions.
Installation
pip install tvi-footballindex
Quick Start
Basic Example with Sample Data
import pandas as pd
from tvi_footballindex.tvi.calculator import calculate_tvi, aggregate_tvi_by_player
# Create sample event data
events_df = pd.DataFrame({
'player_id': [1, 1, 2, 2, 1, 2],
'event_name': ['pass', 'dribble', 'shot', 'pass', 'tackle', 'interception'],
'x': [30, 60, 80, 70, 20, 40], # x-coordinate (0-100)
'y': [50, 40, 60, 30, 50, 20], # y-coordinate (0-100)
'game_id': [1, 1, 1, 1, 1, 1],
'team_id': [101, 101, 102, 102, 101, 102]
})
# Create playtime data (in minutes)
playtime_df = pd.DataFrame({
'player_id': [1, 2],
'play_time': [90, 75],
'game_id': [1, 1],
'team_id': [101, 102]
})
# Calculate TVI
tvi_results = calculate_tvi(events_df, playtime_df)
print("Game-level TVI:")
print(tvi_results[['player_id', 'action_diversity', 'TVI']].head())
# Aggregate across all games for each player
player_tvi = aggregate_tvi_by_player(tvi_results)
print("\nPlayer-level TVI:")
print(player_tvi[['player_id', 'action_diversity', 'TVI']].head())
Required Data Format
Your data needs two DataFrames:
Events DataFrame must contain:
player_id: Unique player identifierevent_name: Type of action (e.g., 'pass', 'shot', 'tackle')x,y: Coordinates on the pitch (0-100 scale recommended)game_id: Game identifierteam_id: Team identifier
Playtime DataFrame must contain:
player_id: Unique player identifierplay_time: Minutes played in the gamegame_id: Game identifierteam_id: Team identifier
Customization
Custom Column Names
If your data uses different column names:
tvi_results = calculate_tvi(
events_df,
playtime_df,
player_id_col='player_uuid',
event_name_col='action_type',
x_col='pos_x',
y_col='pos_y'
)
Custom Pitch Zones
The default creates a 3×3 grid (9 zones). You can customize this:
# Create a 4×4 grid with 16 zones
custom_zones = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
tvi_results = calculate_tvi(
events_df,
playtime_df,
zone_map=custom_zones
)
Scaling Factor
Adjust the TVI scaling constant (default is ~2.05):
tvi_results = calculate_tvi(
events_df,
playtime_df,
C=3.0 # Higher values increase TVI scores
)
Working with F24 Data
If you have Wyscout F24 XML files:
from tvi_footballindex.parsing import f24_parser
# Parse F24 files from a folder
events_df = f24_parser.parsef24_folder("path/to/f24_folder")
# Calculate playtime (minimum 30 minutes to be included)
playtime_df = f24_parser.calculate_player_playtime(events_df, min_playtime=30)
# Extract specific action types
passes = f24_parser.get_progressive_passes(events_df)
dribbles = f24_parser.get_dribbles(events_df)
shots = f24_parser.get_shots_on_target(events_df)
# ... other action extractors available
# Combine all actions
all_actions = pd.concat([passes, dribbles, shots])
# Calculate TVI
tvi_results = calculate_tvi(all_actions, playtime_df)
Understanding the Results
The main metrics returned are:
action_diversity: Weighted or unweighted count of unique action-zone combinations, depending on configurationTVI: Main versatility score (0-1, higher = more versatile)TVI_entropy: Alternative entropy-based score (optional)shannon_entropy: Raw entropy of action distribution
API Reference
Core Functions
calculate_tvi(events_df, playtime_df, **kwargs)
Calculate TVI scores for each player in each game.
Parameters:
events_df(DataFrame): Event data with coordinatesplaytime_df(DataFrame): Playing time dataplayer_id_col(str): Column name for player IDs (default: 'player_id')event_name_col(str): Column name for event types (default: 'event_name')x_col,y_col(str): Column names for coordinates (default: 'x', 'y')C(float): Scaling constant (default: 90/44 ≈ 2.05)zone_map(list): Grid defining pitch zonesweight_by_quantiles(bool): If True, actions are weighted by rarity (inverse Q95). Default: Trueq_values(dict): Pre-computed action quantiles (per action type). If None, computed on the fly.q_level(float): Quantile level for rarity weighting (default: 0.95).
Returns: DataFrame with TVI scores per player per game
aggregate_tvi_by_player(tvi_df, **kwargs)
Aggregate game-level TVI into player-level statistics.
Parameters:
tvi_df(DataFrame): Output fromcalculate_tvi()player_id_col(str): Column name for player IDsplaytime_col(str): Column name for playtime
Returns: DataFrame with aggregated TVI per player
Examples and Use Cases
- Squad Analysis: Compare versatility across your team
- Recruitment: Identify versatile players in other teams
- Tactical Analysis: Understand how formation changes affect versatility
- Player Development: Track versatility improvement over time
Contributing
Contributions welcome! Please feel free to submit issues or pull requests.
License
MIT License - see LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tvi_footballindex-0.3.0.tar.gz.
File metadata
- Download URL: tvi_footballindex-0.3.0.tar.gz
- Upload date:
- Size: 764.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fcc2c67a4a2012a7abe8086abbf3498fcd16d7a740843cfa73d86b18353c10d2
|
|
| MD5 |
9e3308c7eb6b6d52507f7eaba3198490
|
|
| BLAKE2b-256 |
80d26af07c8d1543f87954343805d18a281aa29509b6bbb242e11ff73765474e
|
File details
Details for the file tvi_footballindex-0.3.0-py3-none-any.whl.
File metadata
- Download URL: tvi_footballindex-0.3.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c39c7f1d8e837d8cba9844dd11b6581d56d9819b4d91b34faa1772deb269be1
|
|
| MD5 |
290693dbf70c43966aee0d01c3fde2bb
|
|
| BLAKE2b-256 |
e1e5da761bb533fd1d585f4dd1ea5cbcd7a07f8a16806de32266f6b61123ec06
|