← Back to list

Part 1: Making Sense of MLB’s API — A Step-by-Step Guide in R

For those of you who don’t know me (which is likely the majority of you… because I’m a stranger… on the internet) I am a huge baseball fan…

Kyle Miller · 2025-01-06 04:32 · 51 claps · 4.2 min read paywalled
#baseball #r-tutorial #data-science #data-wrangling #sports-analytics
Open on Medium ↗
Wiki topics: ML · Machine Learning GRW · Growth & Analytics 🔬 · Science · General ⚾ · Baseball 🏆 · Sports · General

Part 1: Making Sense of MLB’s API — A Step-by-Step Guide in R

Thanks ChatGPT !

Thanks ChatGPT !

For those of you who don’t know me (which is likely the majority of you… because I’m a stranger… on the internet) I am a huge baseball fan. Fortunately, my father blessed me at a young age and convinced me to become a fan of the Boston Red Sox which I obliged.

Note: If you or a loved one is a New York Yankee fan you are legally obligated to stop reading this article immediately, seek medical attention from a qualified medical professional, and may be entitled to financial compensation. Also, if the “Evil Empire” is still in the room with us, it had to be tough losing out on Juan Soto to your “little” brother this offseason…

I feel better. As I was saying, being a Red Sox fan since the earlier 2000’s has been a truly wonderful experience. I mean I was basically a toddler when the Sox broke ‘The Curse’, so I didn’t endure that misery firsthand. Then they went on an unprecedented run, winning it all in ’04, ’07, ’13 (Fear the Beard), and ’18 (what curse?). Speaking of 2018, here’s a quick video that personifies how dominate that 2018 team was… even against the bIg, BaD dOdGeRs…

[embed]

I mean Manny Machado is no slouch (58 career WAR, 300+ HRs, and roughly a .280 career average) but he needed a tennis racket, a map, and a blessing from the Vatican to stand a chance against Sale in that at bat.

Now that you know where I stand as a fan, let’s get to the actual point of this article. Hopefully the title was clear enough to indicate this is just Part 1 of several (could be 8… could be 2… this could be it I have no idea) articles I intend to write focused on manipulating MLB data in R. This may or may not be a surprise to you, but the MLB Stats API offers a wealth of data on game scores, player stats, team details, and even stadium information associated to each ball club. For this article, we’ll focus on retrieving live game scores for a single day and exploring some associated team statistics (e.g., win-loss record, home vs. away splits).

Important Note: During the offseason the API endpoint will return ‘NA’… because there are no games happening… because it’s the offseason… and no games are happening.

Step 1: Installing Necessary Libraries

Before we begin, make sure you have the following R libraries installed:

# Install these packages if you don't already have them
install.packages(c("httr", "jsonlite", "dplyr", "tibble", "stringr", "tidyr"))
  • **httr**: Basically a wrapper for traditional curl commands associated with accessing modern APIs.
  • **jsonlite**: Speaking of modern APIs, it is few in far where an API does not return data in JSON format. This package helps you handle it.
  • **dplyr**: Bread and butter data manipulation package for R. Regardless of the project requirements, you should probably start with initializing dplyr.
  • **tibble**: This will help create cleaner, more straightforward data frames for further manipulation.
  • **stringr**: For all of the pesky regex commands and string manipulation you might require during your journey through the jungle.
  • **tidyr**: Makes standardizing your data across multiple files and projects a walk in the park (allegedly).

Step 2: The Function

Here’s a function to fetch and parse data for today’s MLB games. This function directly interacts with the MLB API and returns detailed game information in a manageable format for further manipulation.

Is it perfect? No! But it gets the job done and will serve as an excellent starting point for your specific use case. Feel free to comment your tweaks (corrections) on the article so I can gauge the collective intelligence of my readers…

# Yeah I know the name needs some work...
ParserTodayGame <- function() {
  # Initial GET Call to Today's Game API
  res <- GET("http://statsapi.mlb.com/api/v1/schedule/games/?sportId=1")

  # Create raw data frame
  data <- fromJSON(rawToChar(res$content), flatten = TRUE)

  # Convert raw data frame to unlisted tibble
  dataRaw <- enframe(unlist(data))

  # Replace '.' with '_'
  # Simply helps later down the road with column manipulation
  rgxDelim <- "\\."
  dataRaw$name <- str_replace_all(dataRaw$name, rgxDelim, "_")

  # Remove digits associated to column names
  cleanedNames <- str_replace_all(dataRaw$name, "[:digit:]", "")

  # Create list of unique columns
  uniqueColumns <- unique(cleanedNames)

  # Columns for specific game information
  # Not required... I just don't care about the other columns
  todaysGamesColumns <- uniqueColumns[11:65]

  # Determine number of games happening today
  numGames <- dataRaw[dataRaw$name == "totalItems",]

  # Loop through each column name
  # Create a new dataframe with column names
  parsedTodaysGames <- data.frame(matrix(nrow = as.integer(numGames$value), ncol = length(todaysGamesColumns)))
  colnames(parsedTodaysGames) <- todaysGamesColumns

  for(i in 1:length(todaysGamesColumns)){
    values <- dataRaw %>%
      filter(grepl(todaysGamesColumns[i], dataRaw$name))
    if (length(values$value) > as.integer(numGames$value)){
      values <- values[1:as.integer(numGames$value),]
    }
    parsedTodaysGames[,i] <- values$value
  }
  return(parsedTodaysGames)
}

Step 3: What does the data look like?

So let’s just say (for fun) you copy and pasted the above code block and are just rip roaring ready to run it. What do you expect the data to look like? Simply run the code below and see if my rambling comments actual explain what is going on in the code.

# Fetch and parse today's MLB games
letsSeeWhatHappens <- ParserTodayGame()

So ‘letsSeeWhatHappens’ everything you dreamed of and more? Unlikely, however there is some really good info that could be used in a variety of ways. For example, the ‘dates_games_status_abstractGameState’ gives the current status of the game in questions, whether it’s live, in pre-game, completed, canceled, or delayed. The possibilities are endless with the 55!!! columns returned within the dataset.

Step 4: Enhancements and Possible Next Steps

  • Automate Updates: Schedule the script to run daily and save results locally. I suggest saving at least one day of data into a MySQL database (so offseason development can continue).
  • Build a Dashboard: Integrate this function into a Shiny dashboard for interactive exploration (Maybe part II will address this very step…).
  • Analyze Player Stats: Access additional API endpoints to retrieve player-specific data and compare performances.

Final Thoughts

Fetching and analyzing MLB data using R is anything but straightforward and this simple function is just the beginning. Try customizing it to suit your specific interests or enhance it with additional data processing and visualization techniques.

Happy coding, and enjoy exploring MLB stats! Stay tuned for Part II!


메타데이터
post_id
d189b2bf4ddf
slug
part-1-making-sense-of-mlbs-api-a-step-by-step-guide-in-r-d189b2bf4ddf
url
https://medium.com/@kylemiller014/part-1-making-sense-of-mlbs-api-a-step-by-step-guide-in-r-d189b2bf4ddf
canonical_url
https://medium.com/@kylemiller014/part-1-making-sense-of-mlbs-api-a-step-by-step-guide-in-r-d189b2bf4ddf
author_url
https://medium.com/@kylemiller014
status
ok
fetched_at
2026-07-24 19:13:54