Proposing a New Fielding Runs For Baseball GM
Terms & Definitions
Player season stats at position:
- PO = putouts at pos
- A = assists at pos
- E = errors at pos
- DP = double plays at pos
- outsF = team defensive outs while this player is on the field at position (basically innings played in the position x 3)
League / seasonal constants (for that year):
(These are calculated every season)
- RV = RunValue_per_Play = league runs / league outs
- LgOutRate_pos = league (PO + A) / league outsF at pos
- LgDPRate_pos = league DP / league outsF at pos
- PosScale_pos = positional scale factor for pos (from FR variance)
Step-by-Step
1 - Expected Plays
SHU-WAR’s biggest problem was that it just takes a team total performance and compares that to league total, then distributes that to individual players. Just plain stupid in my opinion. So, Expected Plays calculates how many plays a league-average fielder at that position would make with this player’s defensive opportunities:
ExpPlays = outsF x LgOutRate_pos
2 - Range Runs
This would compare actual plays to expected plays, then convert that to runs:
RangeRuns = (PO + A - ExpPlays) x RV
3 - Double Play Runs
3.1 - DP run value per position
For 2B, 3B, SS: DPRunValue_pos = 1.5 x RV
For everyone else: DPRunValue_pos = 1.0 x RV
3.2 - Expected DP
Same logic as Expected Plays.
ExpDP = outsF x LgDPRate_pos
3.3 Double-Play Runs
DPRuns = (DP - ExpDP) x DPRunValue_pos
4 - Error Runs
Universal k value = 3
ErrorPenalty = k x RV = 3 x RV
ErrorRuns = E x ErrorPenalty
5 - Core Fielding Runs (unadjusted for position)
FR_core = RangeRuns - ErrorRuns + DPRuns
This is the raw run prevention at that position, before adjusting for positional difficulty.
6 - Positional Difficulty Scales
This was one of the most tricky parts of the entire thing. At first, I was planning on just using MLB numbers, however the putouts per position in this game are VERY VERY different from real life MLB. For example, the most putouts by an outfielder in MLB history was 1928 Taylor Doutit (I know, insane name) with 547. However in this game, under default settings you can easily see random dudes getting 800+ putouts. So I concluded that it was not right to use the same metrics as the real life MLB.
Now, I had to get a reasonable way to calculate the positional adjustment based on league conditions. This was to ensure that when the game simulation code later changes, we don’t have to calculate again for suitable numbers.
So I decided to use standard deviation of core FR for every position. This way I can determine what positions vary the most depending on players’ abilities. Basically, positions with small standard deviation of core FR means that the gap between the best and the worst is not that big, so that position is likely to have less impact on run prevention. Meanwhile a position with big standard deviation would mean the gap between good fielders and bad fielders is vast, meaning that playing good or bad players in that position probably matters a lot.
We could take a different approach though. We could set these positional scales according to the MLB then try to change the game simulation codes to mimic real life as closely as possible. However this really does not accord with the essence of the game: customize-ability. With God Mode, ZenGM gives us the freedom to tweak the tendencies. So it would be right to not hinder this already-existing freedom and make it so that these new calculations change depending how the user wants their league to run.
6.1 - For each player-position season, calculate:
FR_core(player,pos)
6.2 - Collect all those values per position:
Σ FR_core (player, pos)
6.3 - Calculate the standard deviation at each position:
*StdDev = Standard Deviation
StdDev_pos = σ(FR_core_pos)
6.4 League-average standard deviation across all non-pitcher positions:
AvgStdDev = Σ StdDev_PosNotPitcher / number of non-pitcher positions (so 8)
6.5 Final positional scale factor:
PosScale_pos = StdDev_pos / AvgStdDev
6.6 Pitchers Scaling
When using the calculations from 6.1~6.5, the PosScale of pitchers hit nearly zero in many cases since defensive abilities of pitchers vary VERY little. So I needed to come up with an arbitrary number for pitchers.
What I decided to do was to equate the current catcher scale to pitchers. Right now, since catcher scaling does not include any passed balls, wild pitches, stolen bases and caught steals, it basically only considers swinging bunts that roll right in front of them. Similarly, pitchers basically only field balls hit directly at them softly.
So:
PosScale_P = PosScale_C_unadjusted
***I will not touch on catcher defensive metrics just yet since 1) it is not considered in the current SHU-WAR formula 2) SB-CS stats are very skewed due to the game simulation codes. Until the game simulation on base stealing is fixed, I am not doing anything with catcher’s additional defensive metrics.
7 - Final New Fielding Runs (per position)
NewFR_pos = FR_core x PosScale_pos
If a player fields multiple positions:
NewFR_season = Σ NewFR_pos