tvi-footballindex


Nametvi-footballindex JSON
Version 0.3.0 PyPI version JSON
download
home_pageNone
SummaryA Python library for calculating Tactical Versatility Index (TVI) in football analytics
upload_time2025-08-20 15:35:12
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords football soccer analytics tactical versatility index sports data-analysis tvi f24 performance-metrics
VCS
bugtrack_url
requirements pandas tqdm
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # TVI Football Index

[![PyPI version](https://badge.fury.io/py/tvi-footballindex.svg)](https://badge.fury.io/py/tvi-footballindex)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/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

```bash
pip install tvi-footballindex
```

## Quick Start

### Basic Example with Sample Data

```python
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:

```python
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:

```python
# 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):

```python
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:

```python
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](LICENSE) file for details.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "tvi-footballindex",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "football, soccer, analytics, tactical, versatility, index, sports, data-analysis, tvi, f24, performance-metrics",
    "author": null,
    "author_email": "Luis Doutor Simoes <luis.d.simoes@tecnico.ulisboa.pt>",
    "download_url": "https://files.pythonhosted.org/packages/80/d2/6af07c8d1543f87954343805d18a281aa29509b6bbb242e11ff73765474e/tvi_footballindex-0.3.0.tar.gz",
    "platform": null,
    "description": "# TVI Football Index\r\n\r\n[![PyPI version](https://badge.fury.io/py/tvi-footballindex.svg)](https://badge.fury.io/py/tvi-footballindex)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\r\n\r\nA 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.\r\n\r\n## What is TVI?\r\n\r\nThe Tactical Versatility Index measures player versatility by:\r\n- **Action Diversity**: How many different types of actions a player performs\r\n- **Spatial Coverage**: How many different pitch zones a player is active in\r\n- **Time Normalization**: Adjusting for actual playing time\r\n\r\nHigher TVI scores indicate more versatile players who contribute across multiple areas and action types.\r\nThe 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.\r\n\r\n## Installation\r\n\r\n```bash\r\npip install tvi-footballindex\r\n```\r\n\r\n## Quick Start\r\n\r\n### Basic Example with Sample Data\r\n\r\n```python\r\nimport pandas as pd\r\nfrom tvi_footballindex.tvi.calculator import calculate_tvi, aggregate_tvi_by_player\r\n\r\n# Create sample event data\r\nevents_df = pd.DataFrame({\r\n    'player_id': [1, 1, 2, 2, 1, 2],\r\n    'event_name': ['pass', 'dribble', 'shot', 'pass', 'tackle', 'interception'],\r\n    'x': [30, 60, 80, 70, 20, 40],  # x-coordinate (0-100)\r\n    'y': [50, 40, 60, 30, 50, 20],  # y-coordinate (0-100)\r\n    'game_id': [1, 1, 1, 1, 1, 1],\r\n    'team_id': [101, 101, 102, 102, 101, 102]\r\n})\r\n\r\n# Create playtime data (in minutes)\r\nplaytime_df = pd.DataFrame({\r\n    'player_id': [1, 2],\r\n    'play_time': [90, 75],\r\n    'game_id': [1, 1],\r\n    'team_id': [101, 102]\r\n})\r\n\r\n# Calculate TVI\r\ntvi_results = calculate_tvi(events_df, playtime_df)\r\nprint(\"Game-level TVI:\")\r\nprint(tvi_results[['player_id', 'action_diversity', 'TVI']].head())\r\n\r\n# Aggregate across all games for each player\r\nplayer_tvi = aggregate_tvi_by_player(tvi_results)\r\nprint(\"\\nPlayer-level TVI:\")\r\nprint(player_tvi[['player_id', 'action_diversity', 'TVI']].head())\r\n```\r\n\r\n### Required Data Format\r\n\r\nYour data needs two DataFrames:\r\n\r\n**Events DataFrame** must contain:\r\n- `player_id`: Unique player identifier\r\n- `event_name`: Type of action (e.g., 'pass', 'shot', 'tackle')\r\n- `x`, `y`: Coordinates on the pitch (0-100 scale recommended)\r\n- `game_id`: Game identifier\r\n- `team_id`: Team identifier\r\n\r\n**Playtime DataFrame** must contain:\r\n- `player_id`: Unique player identifier  \r\n- `play_time`: Minutes played in the game\r\n- `game_id`: Game identifier\r\n- `team_id`: Team identifier\r\n\r\n## Customization\r\n\r\n### Custom Column Names\r\n\r\nIf your data uses different column names:\r\n\r\n```python\r\ntvi_results = calculate_tvi(\r\n    events_df, \r\n    playtime_df,\r\n    player_id_col='player_uuid',\r\n    event_name_col='action_type',\r\n    x_col='pos_x',\r\n    y_col='pos_y'\r\n)\r\n```\r\n\r\n### Custom Pitch Zones\r\n\r\nThe default creates a 3\u00d73 grid (9 zones). You can customize this:\r\n\r\n```python\r\n# Create a 4\u00d74 grid with 16 zones\r\ncustom_zones = [\r\n    [1, 2, 3, 4],\r\n    [5, 6, 7, 8], \r\n    [9, 10, 11, 12],\r\n    [13, 14, 15, 16]\r\n]\r\n\r\ntvi_results = calculate_tvi(\r\n    events_df, \r\n    playtime_df, \r\n    zone_map=custom_zones\r\n)\r\n```\r\n\r\n### Scaling Factor\r\n\r\nAdjust the TVI scaling constant (default is ~2.05):\r\n\r\n```python\r\ntvi_results = calculate_tvi(\r\n    events_df, \r\n    playtime_df,\r\n    C=3.0  # Higher values increase TVI scores\r\n)\r\n```\r\n\r\n## Working with F24 Data\r\n\r\nIf you have Wyscout F24 XML files:\r\n\r\n```python\r\nfrom tvi_footballindex.parsing import f24_parser\r\n\r\n# Parse F24 files from a folder\r\nevents_df = f24_parser.parsef24_folder(\"path/to/f24_folder\")\r\n\r\n# Calculate playtime (minimum 30 minutes to be included)\r\nplaytime_df = f24_parser.calculate_player_playtime(events_df, min_playtime=30)\r\n\r\n# Extract specific action types\r\npasses = f24_parser.get_progressive_passes(events_df)\r\ndribbles = f24_parser.get_dribbles(events_df)\r\nshots = f24_parser.get_shots_on_target(events_df)\r\n# ... other action extractors available\r\n\r\n# Combine all actions\r\nall_actions = pd.concat([passes, dribbles, shots])\r\n\r\n# Calculate TVI\r\ntvi_results = calculate_tvi(all_actions, playtime_df)\r\n```\r\n\r\n## Understanding the Results\r\n\r\nThe main metrics returned are:\r\n\r\n- **`action_diversity`**: Weighted or unweighted count of unique action-zone combinations, depending on configuration\r\n- **`TVI`**: Main versatility score (0-1, higher = more versatile)  \r\n- **`TVI_entropy`**: Alternative entropy-based score (optional)\r\n- **`shannon_entropy`**: Raw entropy of action distribution\r\n\r\n## API Reference\r\n\r\n### Core Functions\r\n\r\n#### `calculate_tvi(events_df, playtime_df, **kwargs)`\r\nCalculate TVI scores for each player in each game.\r\n\r\n**Parameters:**\r\n- `events_df` (DataFrame): Event data with coordinates\r\n- `playtime_df` (DataFrame): Playing time data\r\n- `player_id_col` (str): Column name for player IDs (default: 'player_id')\r\n- `event_name_col` (str): Column name for event types (default: 'event_name') \r\n- `x_col`, `y_col` (str): Column names for coordinates (default: 'x', 'y')\r\n- `C` (float): Scaling constant (default: 90/44 \u2248 2.05)\r\n- `zone_map` (list): Grid defining pitch zones\r\n- `weight_by_quantiles` (bool): If True, actions are weighted by rarity (inverse Q95). Default: True\r\n- `q_values` (dict): Pre-computed action quantiles (per action type). If None, computed on the fly.\r\n- `q_level` (float): Quantile level for rarity weighting (default: 0.95).\r\n\r\n**Returns:** DataFrame with TVI scores per player per game\r\n\r\n#### `aggregate_tvi_by_player(tvi_df, **kwargs)`\r\nAggregate game-level TVI into player-level statistics.\r\n\r\n**Parameters:**\r\n- `tvi_df` (DataFrame): Output from `calculate_tvi()`\r\n- `player_id_col` (str): Column name for player IDs\r\n- `playtime_col` (str): Column name for playtime\r\n\r\n**Returns:** DataFrame with aggregated TVI per player\r\n\r\n## Examples and Use Cases\r\n\r\n- **Squad Analysis**: Compare versatility across your team\r\n- **Recruitment**: Identify versatile players in other teams  \r\n- **Tactical Analysis**: Understand how formation changes affect versatility\r\n- **Player Development**: Track versatility improvement over time\r\n\r\n## Contributing\r\n\r\nContributions welcome! Please feel free to submit issues or pull requests.\r\n\r\n## License\r\n\r\nMIT License - see [LICENSE](LICENSE) file for details.\r\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A Python library for calculating Tactical Versatility Index (TVI) in football analytics",
    "version": "0.3.0",
    "project_urls": {
        "Homepage": "https://github.com/LuisSimoes17/TVI_footballindex",
        "Issues": "https://github.com/LuisSimoes17/TVI_footballindex/issues",
        "Repository": "https://github.com/LuisSimoes17/TVI_footballindex.git"
    },
    "split_keywords": [
        "football",
        " soccer",
        " analytics",
        " tactical",
        " versatility",
        " index",
        " sports",
        " data-analysis",
        " tvi",
        " f24",
        " performance-metrics"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e1e5da761bb533fd1d585f4dd1ea5cbcd7a07f8a16806de32266f6b61123ec06",
                "md5": "290693dbf70c43966aee0d01c3fde2bb",
                "sha256": "7c39c7f1d8e837d8cba9844dd11b6581d56d9819b4d91b34faa1772deb269be1"
            },
            "downloads": -1,
            "filename": "tvi_footballindex-0.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "290693dbf70c43966aee0d01c3fde2bb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 22124,
            "upload_time": "2025-08-20T15:35:10",
            "upload_time_iso_8601": "2025-08-20T15:35:10.483308Z",
            "url": "https://files.pythonhosted.org/packages/e1/e5/da761bb533fd1d585f4dd1ea5cbcd7a07f8a16806de32266f6b61123ec06/tvi_footballindex-0.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "80d26af07c8d1543f87954343805d18a281aa29509b6bbb242e11ff73765474e",
                "md5": "9e3308c7eb6b6d52507f7eaba3198490",
                "sha256": "fcc2c67a4a2012a7abe8086abbf3498fcd16d7a740843cfa73d86b18353c10d2"
            },
            "downloads": -1,
            "filename": "tvi_footballindex-0.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "9e3308c7eb6b6d52507f7eaba3198490",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 764809,
            "upload_time": "2025-08-20T15:35:12",
            "upload_time_iso_8601": "2025-08-20T15:35:12.538651Z",
            "url": "https://files.pythonhosted.org/packages/80/d2/6af07c8d1543f87954343805d18a281aa29509b6bbb242e11ff73765474e/tvi_footballindex-0.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-20 15:35:12",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "LuisSimoes17",
    "github_project": "TVI_footballindex",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "pandas",
            "specs": [
                [
                    ">=",
                    "1.3.0"
                ]
            ]
        },
        {
            "name": "tqdm",
            "specs": [
                [
                    ">=",
                    "4.60.0"
                ]
            ]
        }
    ],
    "lcname": "tvi-footballindex"
}
        
Elapsed time: 1.14305s