FIP (Fielding Independent Pitching)
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 performance | Evaluating actual past results |
| Identifying luck (good or bad) | Award voting (Cy Young) |
| Comparing pitchers across teams | Pitcher has proven contact management skills |
| Small sample analysis | Full season evaluation |
FIP Benchmarks
| FIP Range | Rating | Description |
|---|---|---|
| < 2.50 | Exceptional | Elite ace; historically rare |
| 2.50 - 3.00 | Excellent | Cy Young caliber |
| 3.00 - 3.50 | Above Average | Strong #2-3 starter |
| 3.50 - 4.00 | Average | Solid middle rotation |
| 4.00 - 4.50 | Below Average | Back-end starter |
| > 4.50 | Poor | Below 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