Skip to main content

TVI Football Index

PyPI version License: MIT

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 identifier
  • event_name: Type of action (e.g., 'pass', 'shot', 'tackle')
  • x, y: Coordinates on the pitch (0-100 scale recommended)
  • game_id: Game identifier
  • team_id: Team identifier

Playtime DataFrame must contain:

  • player_id: Unique player identifier
  • play_time: Minutes played in the game
  • game_id: Game identifier
  • team_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 configuration
  • TVI: 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 coordinates
  • playtime_df (DataFrame): Playing time data
  • player_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 zones
  • weight_by_quantiles (bool): If True, actions are weighted by rarity (inverse Q95). Default: True
  • q_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 from calculate_tvi()
  • player_id_col (str): Column name for player IDs
  • playtime_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.

Metadata

Release files for tvi-footballindex 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tvi-footballindex 0.3.0
File Size Uploaded
tvi_footballindex-0.3.0.tar.gz 764.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for tvi-footballindex 0.3.0
File Interpreter ABI Platform
tvi_footballindex-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 786.9 kB

Release files / tvi_footballindex-0.3.0.tar.gz

Download URL tvi_footballindex-0.3.0.tar.gz
Size 764.8 kB
Tags Source
SHA-256 checksum
How to use checksums
fcc2c67a4a2012a7abe8086abbf3498fcd16d7a740843cfa73d86b18353c10d2
BLAKE2b-256 checksum
How to use checksums
80d26af07c8d1543f87954343805d18a281aa29509b6bbb242e11ff73765474e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.5

Release files / tvi_footballindex-0.3.0-py3-none-any.whl

Download URL tvi_footballindex-0.3.0-py3-none-any.whl
Size 22.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7c39c7f1d8e837d8cba9844dd11b6581d56d9819b4d91b34faa1772deb269be1
BLAKE2b-256 checksum
How to use checksums
e1e5da761bb533fd1d585f4dd1ea5cbcd7a07f8a16806de32266f6b61123ec06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page