FIP (Fielding Independent Pitching)

Intermediate 10 min read 1 views Nov 26, 2025

FIP Explained: Fielding Independent Pitching

Fielding Independent Pitching (FIP) is one of the most important advanced metrics in modern baseball analytics. Developed by Tom Tango, FIP measures what a pitcher's ERA should look like based solely on the outcomes they can control: strikeouts, walks, hit by pitches, and home runs.

What FIP Measures

FIP isolates pitcher performance from defensive influence by focusing on three true outcomes plus home runs:

  • Strikeouts (K): Pitcher retired batter without ball in play
  • Walks (BB): Pitcher allowed batter to reach without hitting
  • Hit by Pitch (HBP): Pitcher hit the batter
  • Home Runs (HR): Only hit type FIP considers (can't be fielded)

The FIP Formula

FIP = ((13×HR) + (3×(BB+HBP)) - (2×K)) / IP + FIP_constant

Component Weights:

  • Home Runs (13): Highest weight—worst possible outcome
  • Walks/HBP (3): Free baserunners hurt run prevention
  • Strikeouts (-2): Subtracted—best outcome for pitcher

The FIP constant (typically ~3.10) scales FIP to match league-average ERA.

FIP vs ERA: When to Use Each

Use FIP When...Use ERA When...
Predicting future performanceEvaluating actual past results
Identifying luck (good or bad)Award voting (Cy Young)
Comparing pitchers across teamsPitcher has proven contact management skills
Small sample analysisFull season evaluation

FIP Benchmarks

FIP RangeRatingDescription
< 2.50ExceptionalElite ace; historically rare
2.50 - 3.00ExcellentCy Young caliber
3.00 - 3.50Above AverageStrong #2-3 starter
3.50 - 4.00AverageSolid middle rotation
4.00 - 4.50Below AverageBack-end starter
> 4.50PoorBelow replacement level

Advanced Variants: xFIP and SIERA

xFIP (Expected FIP)

Replaces actual HR with expected HR based on fly ball rate × league HR/FB%. Normalizes for home run luck.

SIERA (Skill-Interactive ERA)

More complex metric incorporating strikeout rate, walk rate, and ground ball rate with interaction terms. Generally most predictive of future ERA.

Python Implementation

from pybaseball import pitching_stats
import pandas as pd
import matplotlib.pyplot as plt

# Get pitching statistics
stats_2024 = pitching_stats(2024, qual=100)

# Calculate FIP-ERA differential
stats_2024['FIP_ERA_diff'] = stats_2024['FIP'] - stats_2024['ERA']

# Top FIP performers
print("Top 10 Pitchers by FIP (2024)")
print("=" * 60)
top_fip = stats_2024.nsmallest(10, 'FIP')[['Name', 'Team', 'IP', 'ERA', 'FIP', 'xFIP', 'K/9', 'BB/9']]
print(top_fip.to_string(index=False))

# Identify regression candidates
print("\nPitchers Likely to Regress (ERA much better than FIP):")
lucky = stats_2024.nsmallest(10, 'FIP_ERA_diff')[['Name', 'ERA', 'FIP', 'FIP_ERA_diff']]
print(lucky.to_string(index=False))

print("\nPitchers Likely to Improve (ERA much worse than FIP):")
unlucky = stats_2024.nlargest(10, 'FIP_ERA_diff')[['Name', 'ERA', 'FIP', 'FIP_ERA_diff']]
print(unlucky.to_string(index=False))

# Visualization: FIP vs ERA
plt.figure(figsize=(10, 8))
plt.scatter(stats_2024['FIP'], stats_2024['ERA'], alpha=0.6)
plt.plot([2, 6], [2, 6], 'r--', label='Perfect Agreement')
plt.xlabel('FIP', fontsize=12)
plt.ylabel('ERA', fontsize=12)
plt.title('FIP vs ERA (2024 Season)', fontsize=14)
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('fip_vs_era.png', dpi=300)
plt.show()

# Component analysis
stats_2024['HR_component'] = (13 * stats_2024['HR']) / stats_2024['IP']
stats_2024['BB_component'] = (3 * (stats_2024['BB'] + stats_2024['HBP'])) / stats_2024['IP']
stats_2024['K_component'] = (2 * stats_2024['SO']) / stats_2024['IP']

print("\nFIP Component Analysis (Top 5 by FIP):")
components = stats_2024.nsmallest(5, 'FIP')[['Name', 'FIP', 'K/9', 'BB/9', 'HR/9']]
print(components.to_string(index=False))

# Year-to-year stability comparison
stats_2023 = pitching_stats(2023, qual=100)
merged = pd.merge(
    stats_2024[['IDfg', 'Name', 'FIP', 'ERA']],
    stats_2023[['IDfg', 'FIP', 'ERA']],
    on='IDfg', suffixes=('_2024', '_2023')
)

fip_corr = merged['FIP_2023'].corr(merged['FIP_2024'])
era_corr = merged['ERA_2023'].corr(merged['ERA_2024'])

print(f"\nYear-to-Year Correlation:")
print(f"FIP: {fip_corr:.3f}")
print(f"ERA: {era_corr:.3f}")
print(f"FIP is {((fip_corr - era_corr) / era_corr * 100):.1f}% more stable")

R Implementation

library(baseballr)
library(dplyr)
library(ggplot2)

# Get pitching data
fg_pitching <- fg_pitch_leaders(
  startseason = 2024,
  endseason = 2024,
  qual = 100
)

# Calculate FIP-ERA differential
fg_pitching <- fg_pitching %>%
  mutate(
    FIP_ERA_diff = FIP - ERA,
    luck_status = case_when(
      FIP_ERA_diff > 0.5 ~ "Unlucky",
      FIP_ERA_diff < -0.5 ~ "Lucky",
      TRUE ~ "Neutral"
    )
  )

# Top FIP performers
cat("Top 10 Pitchers by FIP (2024)\n")
top_fip <- fg_pitching %>%
  select(Name, Team, IP, ERA, FIP, xFIP, `K/9`, `BB/9`) %>%
  arrange(FIP) %>%
  head(10)
print(top_fip)

# Regression candidates
cat("\nLucky Pitchers (ERA << FIP):\n")
lucky <- fg_pitching %>%
  select(Name, ERA, FIP, FIP_ERA_diff) %>%
  arrange(FIP_ERA_diff) %>%
  head(10)
print(lucky)

# Visualization: FIP vs ERA with luck indicators
ggplot(fg_pitching, aes(x = FIP, y = ERA, color = luck_status)) +
  geom_point(size = 3, alpha = 0.7) +
  geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "red") +
  scale_color_manual(values = c(
    "Unlucky" = "#E74C3C",
    "Neutral" = "#95A5A6",
    "Lucky" = "#3498DB"
  )) +
  labs(
    title = "FIP vs ERA: Identifying Lucky and Unlucky Pitchers",
    x = "FIP (Fielding Independent Pitching)",
    y = "ERA (Earned Run Average)",
    color = "Performance"
  ) +
  theme_minimal()

ggsave("fip_era_comparison.png", width = 12, height = 8, dpi = 300)

# FIP category summary
fip_summary <- fg_pitching %>%
  mutate(
    FIP_category = case_when(
      FIP < 3.00 ~ "Elite",
      FIP < 3.75 ~ "Above Avg",
      FIP < 4.25 ~ "Average",
      TRUE ~ "Below Avg"
    )
  ) %>%
  group_by(FIP_category) %>%
  summarise(
    count = n(),
    avg_ERA = mean(ERA),
    avg_FIP = mean(FIP),
    avg_K9 = mean(`K/9`),
    avg_BB9 = mean(`BB/9`)
  )
print(fip_summary)

Key Takeaways

  • FIP isolates pitcher skill: Focuses on outcomes pitchers control
  • More predictive than ERA: Better for forecasting future performance
  • FIP-ERA gaps reveal luck: Large differences indicate regression potential
  • xFIP normalizes HR luck: Uses expected HR based on fly ball rate
  • SIERA is most sophisticated: Accounts for skill interactions
  • Use both metrics together: FIP for projection, ERA for actual results

Discussion

Have questions or feedback? Join our community discussion on Discord or GitHub Discussions.