Skip to main content

Retrieve baseball data in Python

Project description

polars-baseball

PyPI version Python versions CI Codecov License Downloads

Languages: English | Traditional Chinese

polars-baseball is The unified Polars-native baseball data SDK: a typed, async-first Python library for retrieving MLB and baseball analytics data from Statcast, Baseball Savant, FanGraphs, Baseball Reference, Lahman, Retrosheet, and the MLB Stats API.

If you searched for python baseball data, python statcast, fangraphs python, baseball savant api, pybaseball alternative, or polars dataframe baseball, this project is built for the workflow where data should land directly in polars.DataFrame instead of going through pandas first.

Why use polars-baseball instead of pybaseball?

pybaseball is useful and established. polars-baseball is aimed at a different execution model: async data ingestion, native Polars output, and one consistent entry point across multiple baseball data providers.

Feature pybaseball polars-baseball
Polars native No Yes
Async data fetching No Yes
Statcast / Baseball Savant Yes Yes
FanGraphs Yes Yes
MLB Stats API Limited Yes
Lahman / Retrosheet workflows Partial Yes
Built-in cache Partial Yes
Typed public API Partial Yes

Typical pandas-first workflow:

pybaseball -> pandas -> convert to Polars -> analysis

polars-baseball workflow:

polars-baseball -> Polars -> analysis

Key Features

  • Polars-native data: Public data-fetching APIs return polars.DataFrame unless an API reference explicitly documents a non-tabular contract.
  • Async-first engine: Data-fetching APIs are async def and can be composed with your own async workflows.
  • Multiple providers: Statcast, Baseball Savant, FanGraphs, Baseball Reference, Lahman, Retrosheet, MLB Stats API, and player ID workflows.
  • Opt-in file cache: Large workflows can cache repeated network requests as Parquet files.
  • Service-ready context: BaseballContext lets long-running apps control HTTP and cache resources explicitly.
  • Explicit HTTP policy: HttpClient exposes timeout, retry, and BRef rate-limit settings.

Installation

pip install polars-baseball

For local development:

git clone https://github.com/nicko4o/polars-baseball
cd polars-baseball
uv sync --all-extras

To run visualization examples:

pip install "polars-baseball[plot]"

Quick Start

Statcast pitch-level data

import asyncio

import polars_baseball as pb


async def main() -> None:
    df = await pb.statcast(start_date="2024-05-06", end_date="2024-05-06")
    print(df.head(5))


if __name__ == "__main__":
    asyncio.run(main())

Aggregate directly with Polars

import asyncio

import polars as pl
import polars_baseball as pb


async def main() -> None:
    df = await pb.statcast_pitcher(
        start_date="2024-05-06",
        end_date="2024-05-06",
        player_id=506433,
    )
    summary = df.group_by("pitch_type").agg(
        pl.col("release_speed").mean().alias("mean_speed"),
        pl.len().alias("pitch_count"),
    )
    print(summary.sort("pitch_count", descending=True))


if __name__ == "__main__":
    asyncio.run(main())

FanGraphs leaderboard

import asyncio

import polars_baseball as pb


async def main() -> None:
    df = await pb.fangraphs.batting(
        start_season=2024,
        end_season=2024,
        qual=100,
        max_results=20,
    )
    print(df.head(10))


if __name__ == "__main__":
    asyncio.run(main())

Examples

Runnable examples live in examples/:

Benchmarking

Do not trust performance claims without a reproducible command. Start with:

python examples/benchmark_statcast.py --start-date 2024-04-01 --end-date 2024-04-07

The script reports row count, column count, wall time, and Python allocation peak measured by tracemalloc. Use the same date range, cache state, Python version, and machine when comparing against pandas-first workflows.

Web Services & Concurrency

Calling package functions without context uses the implicit package-level BaseballContext. That default context is convenient for scripts and does not write cache files unless configure_cache() has been called. Long-running concurrent services should manage their own context and pass it into every API call.

from contextlib import asynccontextmanager

from fastapi import FastAPI

import polars_baseball as pb


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with pb.BaseballContext() as context:
        app.state.pb_context = context
        yield


app = FastAPI(lifespan=lifespan)


@app.get("/statcast")
async def get_statcast() -> dict[str, int]:
    df = await pb.statcast(
        start_date="2026-06-01",
        end_date="2026-06-02",
        context=app.state.pb_context,
    )
    return {"rows": df.height}

API Namespace Policy

The package root (import polars_baseball as pb) exposes core convenience APIs and provider namespaces. Use pb.fangraphs, pb.savant, and pb.mlb for provider-specific workflows. Lahman, Retrosheet, Baseball Reference, and player ID workflows remain available from the package root.

Modules prefixed with _, including _schemas, are internal implementation details and are not part of the compatibility contract.

Documentation

Showcase

Projects using polars-baseball:

  • MLB dashboard workflows
  • Chinese baseball website data jobs
  • Threads bot baseball data pipelines

Contributing

See CONTRIBUTING.md for development workflow and architecture notes.

Author

Created and maintained by Nick.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

polars_baseball-0.7.0.tar.gz (112.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

polars_baseball-0.7.0-py3-none-any.whl (143.0 kB view details)

Uploaded Python 3

File details

Details for the file polars_baseball-0.7.0.tar.gz.

File metadata

  • Download URL: polars_baseball-0.7.0.tar.gz
  • Upload date:
  • Size: 112.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for polars_baseball-0.7.0.tar.gz
Algorithm Hash digest
SHA256 23aedf999a1ac022f7852fdc6d946533808a419ed497742b76969060e8ada67f
MD5 82c9c1c82813f8fddaa57e0e9582a6d6
BLAKE2b-256 2830889eca08a1f6cc2e36f34773d0afe27371d0099f9ff04675e67e097980ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for polars_baseball-0.7.0.tar.gz:

Publisher: python-publish.yml on nicko4o/polars-baseball

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file polars_baseball-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: polars_baseball-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 143.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for polars_baseball-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2a3a8cde69ea47f808c14cba41dc323c8f28c2fb81a135879093d7c5805a0534
MD5 ea201fae6de96a981707658ae119bb08
BLAKE2b-256 6d9b52f88566a5fdb2d3b2dd7fe9605e88f0a81bdff514820fd459502a5b3924

See more details on using hashes here.

Provenance

The following attestation bundles were made for polars_baseball-0.7.0-py3-none-any.whl:

Publisher: python-publish.yml on nicko4o/polars-baseball

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page