Skip to content

Commit c5a3deb

Browse files
authored
Merge pull request #21 from ss77995ss/feature/extra-bases-taken
[Feature][Statcast] Extra Bases Taken function
2 parents e559f6e + 7b918f9 commit c5a3deb

File tree

4 files changed

+96
-0
lines changed

4 files changed

+96
-0
lines changed

.python-version

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.11.2

docs/runner_extra_bases_taken.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Statcast Runner Extra Bases Taken
2+
3+
## `runner_extra_bases_taken`
4+
5+
Function to get extra base taken data from each advanced opportunity for a specific runner. Based on Baseball Savant's [Runner Extra Bases Taken](https://baseballsavant.mlb.com/leaderboard/baserunning).
6+
7+
**Examples**
8+
9+
```python
10+
from baseball_stats_python import runner_extra_bases_taken
11+
12+
# Get Corbin Carroll's runner extra bases taken data
13+
runner_extra_bases_taken('682998')
14+
15+
# Get Corbin Carroll's runner extra bases taken data in 2023
16+
runner_extra_bases_taken('682998', season='2023')
17+
18+
# Get Corbin Carroll's runner extra bases taken data in playoffs
19+
runner_extra_bases_taken('682998', game_type=GameType.PLAYOFFS)
20+
```
21+
22+
**Arguments**
23+
24+
| Argument | Data Type | Description |
25+
| -------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
26+
| runner_id (Required) | `str` | The MLBAM ID of the runner. |
27+
| game_type | `str` or `GameType` | The game type to filter by. Can be `R` for regular season, `PO` for playoffs, or `All` for all games. Check enum [GameType](../enums/statcast_leaderboard.py) |
28+
| season | `str` | The season to filter by. The earliest season available is 2016. |
29+
30+
**Return**
31+
32+
A DataFrame with columns that related to the [Runner Extra Bases Taken](https://baseballsavant.mlb.com/leaderboard/baserunning) leaderboard. The DataFrame will represent each advanced opportunity for a specific runner which contains data like `fielder_runs`, `runner_runs`, `base_out_text`, etc.

src/baseball_stats_python/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
minor_statcast_search,
66
)
77
from .statcast.mlbam_id_search import mlbam_id_search
8+
from .statcast.runner_basestealing import runner_basestealing
9+
from .statcast.runner_extra_bases_taken import runner_extra_bases_taken
810
from .statcast.statcast_search import (
911
statcast_batter_search,
1012
statcast_pitcher_search,
@@ -20,4 +22,6 @@
2022
'minor_statcast_batter_search',
2123
'mlbam_id_search',
2224
'catcher_throwing',
25+
'runner_basestealing',
26+
'runner_extra_bases_taken',
2327
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import pandas as pd
2+
import requests
3+
4+
from ..constants import DEFAULT_SEASON
5+
from ..enums.statcast_leaderboard import GameType
6+
7+
session = requests.Session()
8+
9+
API_URL = 'https://baseballsavant.mlb.com/leaderboard/services/baserunning'
10+
11+
12+
def runner_extra_bases_taken(
13+
runner_id: str,
14+
game_type: str | GameType = GameType.REGULAR_SEASON,
15+
season: str = str(DEFAULT_SEASON),
16+
) -> pd.DataFrame:
17+
"""
18+
Get extra base taken data from each advanced opportunity for a specific runner.
19+
ref: https://baseballsavant.mlb.com/leaderboard/baserunning
20+
21+
Args:
22+
runner_id (str): The MLBAM ID of the runner. (Required)
23+
game_type (str | GameType): The game type to filter by. Default is "Regular".
24+
season (str): The season to filter by. The earliest season available is 2016.
25+
Returns:
26+
pd.DataFrame: A DataFrame containing the baserunning data.
27+
"""
28+
29+
if not runner_id:
30+
raise ValueError('runner_id is required')
31+
32+
if not isinstance(game_type, str) and not isinstance(game_type, GameType):
33+
raise ValueError(f'Invalid type for game_type: {type(game_type)}')
34+
35+
if not GameType.has_value(game_type):
36+
raise ValueError(f'Invalid game type: {game_type}')
37+
38+
if int(season) < 2016:
39+
raise ValueError(
40+
f'Invalid season: {season}, The earliest season available is 2016'
41+
)
42+
43+
params = {
44+
'game_type': game_type,
45+
'season_start': season,
46+
'season_end': season,
47+
'n': 0,
48+
}
49+
50+
response = session.get(f'{API_URL}/{runner_id}', params=params)
51+
52+
if response.status_code == 200:
53+
result = response.json()
54+
df = pd.DataFrame(result['data'])
55+
return df
56+
else:
57+
raise Exception(
58+
f'Failed to fetch data: {response.status_code} - {response.text}'
59+
)

0 commit comments

Comments
 (0)