As a recent baseball strategy, it is said that it is better to hit without a sacrifice bunt on the first base without death, but I was wondering if it was really correct, so I checked it. I think the same thing has already been done, but I decided to try it for my own study.
I calculated it using something Monte Carlo method. The language is Python. The code is at the end.
The following striking lines are assumed.
・ All batters are uniform ・ The probability of hits per turn at bat is 30%, and one-third of the hits will be doubles. ・ 35% chance of getting on base per turn at bat ・ If the probability of a double play per turn at bat is 65% and a double play occurs (example: no death or 1st base with one death), 50% of the double play will be a double play. ・ Home base survival rate: For example, in the case of runner 2nd base, 100% will be scored for 2nd base and 50% for single hit. ・ In the case of runner 3rd base, about 10% of the hits are treated as squeeze / sacrifice fly (1 out, 1 score)
There are other detailed conditions depending on the case, but I will omit the explanation. See the code for details (sorry it's hard to see ...).
The handling of the feed bunt is as follows.
・ At the time of no death or one death 1st base, or no death 12th base, advance the runners instead of increasing one out (the former becomes one death or two deaths second base, the latter becomes one death 23rd base). The success rate is 100%.
It is also the case that it is assumed that home runs and triples do not occur in the batter's assumption part, but since the sending bunt is always treated as successful, the sending bunt strategy is set to work in an advantageous way.
The horizontal axis is the number of attack innings, and the vertical axis is the expected score per inning. In addition, the red line shows the fluctuation of the value when the forced measure is taken, and the blue line shows the fluctuation of the value when the sending bunt measure is taken. As shown in the figure, if the hit probability per turn at bat is expected to be about 30% on average, it can be seen that the expected score is higher if a hard-line measure is taken.
I calculated the case where the probability of hits per turn at bat was changed to 25% and the probability of hitting bases per turn at bat was changed to 30%. Other conditions are the same as the previous calculation. As shown in the figure, the expected score is slightly higher when the feed bunt measure is taken.
Not surprisingly, we found that effective strategies change depending on the probability of hits. I haven't tried various conditions, so I can't say it unconditionally, but I feel that there is a turning point where the hit probability per turn at bat is about 25% (or the probability of getting on base per turn at bat is 30%). ..
After that, the number of trial innings is too small for tournament games such as high school baseball, so I think there is a part where it cannot be said that either strategy works effectively. To put it the other way around, I think it's interesting that the colors for each team come out by having various best strategies.
I would like to improve it so that the batting average etc. can be set strictly for each batter, and I think it would be better to include factors such as stolen base.
The code is shown below. It's very verbose and complicated because it's a beginner ... I'd like to improve this as well. The calculation below is for result 2.
Baseball_Simulator_v1.py
#coding: utf-8
#average_Hitting=0.25
#average_go_on_base=0.30
import numpy as np
import random
import matplotlib.pyplot as plt
random.seed(0)
def HitResult(p,runner,out,R):
#no runner
if runner == 0:
if p < 0.:
R = R+1 #homerun
elif p < 0.:
runner = 3 #triple
elif p < 0.083333:
runner = 2 #double
elif p < 0.30:
runner = 1 #single
else:
out = out+1 #out
#runner on base1
elif runner == 1:
if p < 0.:
runner = 0
R = R+2 #two run homerun
elif p < 0.:
runner = 3
R = R+1 #clutch triple
elif p < 0.041666:
runner = 2
R = R+1 #clutch double
elif p < 0.083333:
runner = 23 #double
elif p < 0.166666:
runner = 13 #single with base3
elif p < 0.3:
runner = 12 #single or walk
elif p < 0.65:
out = out+1 #out
else:
runner = 0
out = out+2 #double play
#runner on base2
elif runner == 2:
if p < 0.:
runner = 0
R = R+2 #two run homerun
elif p < 0.:
runner = 3 #clutch triple
R = R+1
elif p < 0.083333:
R = R+1 #clutch double
elif p < 0.166666:
runner = 1
R = R+1 #clutch single
elif p < 0.25:
runner = 13 #single
elif p < 0.30:
runner = 12 #walk
elif p < 0.9:
out = out+1 #out
else:
runner = 0
out = out+2 #double play
#runner on base3
elif runner == 3:
if p < 0.:
runner = 0
R = R+2 #two run homerun
elif p < 0.:
runner = 3
R = R+1 #clutch triple
elif p < 0.083333:
runner = 2
R = R+1 #clutch double
elif p < 0.25:
runner = 1
R = R+1 #clutch single
elif p < 0.30:
runner = 13 #walk
elif p < 0.45:
if out <= 1:
runner = 0
R = R+1
out = out+1 #sacrifice out
elif p < 0.9:
out = out+1 #out
else:
runner = 0
out = out+2 #double play
#runner on base1 and base2
elif runner == 12:
if p < 0.:
runner = 0
R = R+3 #three run homerun
elif p < 0.:
runner = 3
R = R+2 #2 clutches triple
elif p < 0.041666:
runner = 2
R = R+2 #2 clutches double
elif p < 0.083333:
runner = 23
R = R+1 #clutch double
elif p < 0.138888:
runner = 13
R = R+1 #clutch single with base3
elif p < 0.194444:
runner = 12
R = R+1 #clutch single
elif p < 0.30:
runner = 123 #single or walk
elif p < 0.65:
out = out+1 #out
elif p < 0.825:
runner = 2
out = out+2 #double play through base3
elif p < 0.99:
runner = 3
out = out+2 #double play through base2
else:
runner = 0
out = out+3 #triple play
#runner on base1 and base3
elif runner == 13:
if p < 0.:
runner = 0
R = R+3 #three run homerun
elif p < 0.:
runner = 3
R = R+2 #2 clutches triple
elif p < 0.041666:
runner = 2
R = R+2 #2 clutches double
elif p < 0.083333:
runner = 23
R = R+1 #clutch double
elif p < 0.166666:
runner = 13
R = R+1 #clutch single with base3
elif p < 0.25:
runner = 12
R = R+1 #clutch single
elif p < 0.30:
runner = 123 #walk
elif p < 0.45:
if out <= 1:
runner = 1
R = R+1
out = out+1 #sacrifice out
elif p < 0.52:
if out <= 1:
R = R+1
runner = 1
out = out+1 #double play failure
elif p < 0.68:
out = out+1 #out
elif p < 0.84:
runner = 12
out = out+1 #out on home
elif p < 0.99:
if out == 0:
R = R+1
out = out+2 #double play
else:
out = out+3 #triple play
#runner on base2 and base3
elif runner == 23:
if p < 0.:
runner = 0
R = R+3 #three run homerun
elif p < 0.:
runner = 3
R = R+2 #2 clutches triple
elif p < 0.083333:
runner = 2
R = R+2 #2 clutches double
elif p < 0.166666:
runner = 1
R = R+2 #2 clutches single
elif p < 0.25:
runner = 13
R = R+1 #clutch single
elif p < 0.30:
runner = 123 #walk
elif p < 0.45:
if out <= 1:
runner = 2
R = R+1
out = out+1 #sacrifice out
elif p < 0.9:
out = out+1 #out
elif p < 0.995:
runner = 2
out = out+2 #double play
else:
runner = 0
out = out+3 #triple play
#runner on all bases
else:
if p < 0.:
runner = 0
R = R+4 #four run homerun
elif p < 0.:
runner = 3
R = R+3 #3 clutches triple
elif p < 0.041666:
runner = 2
R = R+3 #3 clutches double
elif p < 0.083333:
runner = 23
R = R+2 #2 clutches double
elif p < 0.138888:
runner = 13
R = R+2 #2 clutches single with base3
elif p < 0.194444:
runner = 12
R = R+2 #2 clutches single
elif p < 0.30:
R = R+1 #clutch single or clutch walk
elif p < 0.45:
if out <= 1:
runner = 12
R = R+1
out = out+1 #sacrifice out
elif p < 0.675:
out = out+1 #out
elif p < 0.99:
runner = 23
out = out+2 #double play through home
else:
runner = 0
out = out+3 #triple play
return runner,out,R
def BuntResult(p,runner,out,R):
#no runner
if runner == 0:
if p < 0.:
R = R+1 #homerun
elif p < 0.:
runner = 3 #triple
elif p < 0.1:
runner = 2 #double
elif p < 0.35:
runner = 1 #single
else:
out = out+1 #out
#runner on base1
elif runner == 1:
if out == 2:
if p < 0.:
runner = 0
R = R+2 #two run homerun
elif p < 0.:
runner = 3
R = R+1 #clutch triple
elif p < 0.041666:
runner = 2
R = R+1 #clutch double
elif p < 0.083333:
runner = 23 #double
elif p < 0.166666:
runner = 13 #single with base3
elif p < 0.30:
runner = 12 #single
elif p < 0.65:
out = out+1 #out
else:
runner = 0
out = out+2 #double play
else:
if p < 1.:
runner = 2
out = out+1 #sacrifice bunt
elif p < 999:
out = out+1 #bunt failure
else:
runner = 0
out = out+2 #double play
#runner on base2
elif runner == 2:
if out == 0:
if p < 1.:
runner = 3
out = out+1 #sacrifice bunt
elif p < 999:
out = out+1 #bunt failure
else:
runner = 1
out = out+1 #bunt failure
else:
if p < 0.:
runner = 0
R = R+2 #two run homerun
elif p < 0.:
runner = 3 #clutch triple
R = R+1
elif p < 0.083333:
R = R+1 #clutch double
elif p < 0.166666:
runner = 1
R = R+1 #clutch single
elif p < 0.25:
runner = 13 #single
elif p < 0.30:
runner = 12 #walk
elif p < 0.9:
out = out+1 #out
else:
runner = 0
out = out+2 #double play
#runner on base3
elif runner == 3:
if p < 0.:
runner = 0
R = R+2 #two run homerun
elif p < 0.:
runner = 3
R = R+1 #clutch triple
elif p < 0.083333:
runner = 2
R = R+1 #clutch double
elif p < 0.25:
runner = 1
R = R+1 #clutch single
elif p < 0.30:
runner = 13 #walk
elif p < 0.45:
if out <= 1:
runner = 0
R = R+1
out = out+1 #sacrifice out
elif p < 0.9:
out = out+1 #out
else:
runner = 0
out = out+2 #double play
#runner on base1 and base2
elif runner == 12:
if out == 0:
if p < 1.:
runner = 23
out = out+1 #sacrifice bunt
elif p < 999:
out = out+1 #bunt failure
else:
runner = 2
out = out+2 #bunt failure (double play)
else:
if p < 0.:
runner = 0
R = R+3 #three run homerun
elif p < 0.:
runner = 3
R = R+2 #2 clutches triple
elif p < 0.041666:
runner = 2
R = R+2 #2 clutches double
elif p < 0.083333:
runner = 23
R = R+1 #clutch double
elif p < 0.138888:
runner = 13
R = R+1 #clutch single with base3
elif p < 0.194444:
runner = 12
R = R+1 #clutch single
elif p < 0.30:
runner = 123 #single or walk
elif p < 0.65:
out = out+1 #out
elif p < 0.825:
runner = 2
out = out+2 #double play through base3
elif p < 0.99:
runner = 3
out = out+2 #double play through base2
else:
runner = 0
out = out+3 #triple play
#runner on base1 and base3
elif runner == 13:
if p < 0.:
runner = 0
R = R+3 #three run homerun
elif p < 0.:
runner = 3
R = R+2 #2 clutches triple
elif p < 0.041666:
runner = 2
R = R+2 #2 clutches double
elif p < 0.083333:
runner = 23
R = R+1 #clutch double
elif p < 0.166666:
runner = 13
R = R+1 #clutch single with base3
elif p < 0.25:
runner = 12
R = R+1 #clutch single
elif p < 0.30:
runner = 123 #walk
elif p < 0.45:
if out <= 1:
runner = 1
R = R+1
out = out+1 #sacrifice out
elif p < 0.52:
if out <= 1:
R = R+1
runner = 1
out = out+1 #double play failure
elif p < 0.68:
out = out+1 #out
elif p < 0.84:
runner = 12
out = out+1 #out on home
elif p < 0.99:
if out == 0:
R = R+1
out = out+2 #double play
else:
out = out+3 #triple play
#runner on base2 and base3
elif runner == 23:
if p < 0.:
runner = 0
R = R+3 #three run homerun
elif p < 0.:
runner = 3
R = R+2 #2 clutches triple
elif p < 0.083333:
runner = 2
R = R+2 #2 clutches double
elif p < 0.166666:
runner = 1
R = R+2 #2 clutches single
elif p < 0.25:
runner = 13
R = R+1 #clutch single
elif p < 0.30:
runner = 123 #walk
elif p < 0.45:
if out <= 1:
runner = 2
R = R+1
out = out+1 #sacrifice out
elif p < 0.9:
out = out+1 #out
elif p < 0.995:
runner = 2
out = out+2 #double play
else:
runner = 0
out = out+3 #triple play
#runner on all bases
else:
if p < 0.:
runner = 0
R = R+4 #four run homerun
elif p < 0.:
runner = 3
R = R+3 #3 clutches triple
elif p < 0.041666:
runner = 2
R = R+3 #3 clutches double
elif p < 0.083333:
runner = 23
R = R+2 #2 clutches double
elif p < 0.138888:
runner = 13
R = R+2 #2 clutches single with base3
elif p < 0.194444:
runner = 12
R = R+2 #2 clutches single
elif p < 0.30:
R = R+1 #clutch single or clutch walk
elif p < 0.45:
if out <= 1:
runner = 12
R = R+1
out = out+1 #sacrifice out
elif p < 0.65:
out = out+1 #out
elif p < 0.99:
runner = 23
out = out+2 #double play through home
else:
runner = 0
out = out+3 #triple play
return runner,out,R
#Initial condition
inning = 1
max_inning = 10000
runner = 0
out = 0
R = 0
sum_num1 = 0
sum_num2 = 0
sum_num3 = 0
sum_num4 = 0
sum_num5 = 0
sum_num6 = 0
sum_num7 = 0
sum_num8 = 0
sum_num9 = 0
sum_num10 = 0
R_array_Hit1 = np.zeros((max_inning+1,1))
R_array_Hit2 = np.zeros((max_inning+1,1))
R_array_Hit3 = np.zeros((max_inning+1,1))
R_array_Hit4 = np.zeros((max_inning+1,1))
R_array_Hit5 = np.zeros((max_inning+1,1))
R_array_Hit6 = np.zeros((max_inning+1,1))
R_array_Hit7 = np.zeros((max_inning+1,1))
R_array_Hit8 = np.zeros((max_inning+1,1))
R_array_Hit9 = np.zeros((max_inning+1,1))
R_array_Hit10 = np.zeros((max_inning+1,1))
Exp_R_Hit1 = np.zeros((max_inning+1,1))
Exp_R_Hit2 = np.zeros((max_inning+1,1))
Exp_R_Hit3 = np.zeros((max_inning+1,1))
Exp_R_Hit4 = np.zeros((max_inning+1,1))
Exp_R_Hit5 = np.zeros((max_inning+1,1))
Exp_R_Hit6 = np.zeros((max_inning+1,1))
Exp_R_Hit7 = np.zeros((max_inning+1,1))
Exp_R_Hit8 = np.zeros((max_inning+1,1))
Exp_R_Hit9 = np.zeros((max_inning+1,1))
Exp_R_Hit10 = np.zeros((max_inning+1,1))
#inning_array = np.zeros((max_inning+1,1))
#Simulation in case of hitting
for i in range(1,11):
for inning in range(1,max_inning+1):
while True:
p = random.random()
runner,out,R = HitResult(p,runner,out,R)
if out >= 3:
break
if i == 1:
R_array_Hit1[inning,0] = R
sum_num1 = sum_num1 + R
Exp_R_Hit1[inning,0] = float(sum_num1)/inning
elif i == 2:
R_array_Hit2[inning,0] = R
sum_num2 = sum_num2 + R
Exp_R_Hit2[inning,0] = float(sum_num2)/inning
elif i == 3:
R_array_Hit3[inning,0] = R
sum_num3 = sum_num3 + R
Exp_R_Hit3[inning,0] = float(sum_num3)/inning
elif i == 4:
R_array_Hit4[inning,0] = R
sum_num4 = sum_num4 + R
Exp_R_Hit4[inning,0] = float(sum_num4)/inning
elif i == 5:
R_array_Hit5[inning,0] = R
sum_num5 = sum_num5 + R
Exp_R_Hit5[inning,0] = float(sum_num5)/inning
elif i == 6:
R_array_Hit6[inning,0] = R
sum_num6 = sum_num6 + R
Exp_R_Hit6[inning,0] = float(sum_num6)/inning
elif i == 7:
R_array_Hit7[inning,0] = R
sum_num7 = sum_num7 + R
Exp_R_Hit7[inning,0] = float(sum_num7)/inning
elif i == 8:
R_array_Hit8[inning,0] = R
sum_num8 = sum_num8 + R
Exp_R_Hit8[inning,0] = float(sum_num8)/inning
elif i == 9:
R_array_Hit9[inning,0] = R
sum_num9 = sum_num9 + R
Exp_R_Hit9[inning,0] = float(sum_num9)/inning
else:
R_array_Hit10[inning,0] = R
sum_num10 = sum_num10 + R
Exp_R_Hit10[inning,0] = float(sum_num10)/inning
#Initialize conditions
runner = 0
out = 0
R = 0
inning = inning+1
i = i+1
#Initial condition
inning = 1
max_inning = 10000
runner = 0
out = 0
R = 0
sum_num1 = 0
sum_num2 = 0
sum_num3 = 0
sum_num4 = 0
sum_num5 = 0
sum_num6 = 0
sum_num7 = 0
sum_num8 = 0
sum_num9 = 0
sum_num10 = 0
R_array_Bunt1 = np.zeros((max_inning+1,1))
R_array_Bunt2 = np.zeros((max_inning+1,1))
R_array_Bunt3 = np.zeros((max_inning+1,1))
R_array_Bunt4 = np.zeros((max_inning+1,1))
R_array_Bunt5 = np.zeros((max_inning+1,1))
R_array_Bunt6 = np.zeros((max_inning+1,1))
R_array_Bunt7 = np.zeros((max_inning+1,1))
R_array_Bunt8 = np.zeros((max_inning+1,1))
R_array_Bunt9 = np.zeros((max_inning+1,1))
R_array_Bunt10 = np.zeros((max_inning+1,1))
Exp_R_Bunt1 = np.zeros((max_inning+1,1))
Exp_R_Bunt2 = np.zeros((max_inning+1,1))
Exp_R_Bunt3 = np.zeros((max_inning+1,1))
Exp_R_Bunt4 = np.zeros((max_inning+1,1))
Exp_R_Bunt5 = np.zeros((max_inning+1,1))
Exp_R_Bunt6 = np.zeros((max_inning+1,1))
Exp_R_Bunt7 = np.zeros((max_inning+1,1))
Exp_R_Bunt8 = np.zeros((max_inning+1,1))
Exp_R_Bunt9 = np.zeros((max_inning+1,1))
Exp_R_Bunt10 = np.zeros((max_inning+1,1))
#inning_array = np.zeros((max_inning+1,1))
#Simulation in case of bunt
for i in range(1,11):
for inning in range(1,max_inning+1):
while True:
p = random.random()
runner,out,R = BuntResult(p,runner,out,R)
if out >= 3:
break
if i == 1:
R_array_Bunt1[inning,0] = R
sum_num1 = sum_num1 + R
Exp_R_Bunt1[inning,0] = float(sum_num1)/inning
elif i == 2:
R_array_Bunt2[inning,0] = R
sum_num2 = sum_num2 + R
Exp_R_Bunt2[inning,0] = float(sum_num2)/inning
elif i == 3:
R_array_Bunt3[inning,0] = R
sum_num3 = sum_num3 + R
Exp_R_Bunt3[inning,0] = float(sum_num3)/inning
elif i == 4:
R_array_Bunt4[inning,0] = R
sum_num4 = sum_num4 + R
Exp_R_Bunt4[inning,0] = float(sum_num4)/inning
elif i == 5:
R_array_Bunt5[inning,0] = R
sum_num5 = sum_num5 + R
Exp_R_Bunt5[inning,0] = float(sum_num5)/inning
elif i == 6:
R_array_Bunt6[inning,0] = R
sum_num6 = sum_num6 + R
Exp_R_Bunt6[inning,0] = float(sum_num6)/inning
elif i == 7:
R_array_Bunt7[inning,0] = R
sum_num7 = sum_num7 + R
Exp_R_Bunt7[inning,0] = float(sum_num7)/inning
elif i == 8:
R_array_Bunt8[inning,0] = R
sum_num8 = sum_num8 + R
Exp_R_Bunt8[inning,0] = float(sum_num8)/inning
elif i == 9:
R_array_Bunt9[inning,0] = R
sum_num9 = sum_num9 + R
Exp_R_Bunt9[inning,0] = float(sum_num9)/inning
else:
R_array_Bunt10[inning,0] = R
sum_num10 = sum_num10 + R
Exp_R_Bunt10[inning,0] = float(sum_num10)/inning
#Initialize conditions
runner = 0
out = 0
R = 0
inning = inning+1
i = i+1
ave_Exp_R_Hit = np.zeros((max_inning+1,1))
ave_Exp_R_Bunt = np.zeros((max_inning+1,1))
all_Exp_R_Hit = np.array([])
all_Exp_R_Hit = np.hstack((Exp_R_Hit1,Exp_R_Hit2,Exp_R_Hit3,Exp_R_Hit4,Exp_R_Hit5,Exp_R_Hit6,Exp_R_Hit7,Exp_R_Hit8,Exp_R_Hit9,Exp_R_Hit10))
all_Exp_R_Bunt = np.array([])
all_Exp_R_Bunt = np.hstack((Exp_R_Bunt1,Exp_R_Bunt2,Exp_R_Bunt3,Exp_R_Bunt4,Exp_R_Bunt5,Exp_R_Bunt6,Exp_R_Bunt7,Exp_R_Bunt8,Exp_R_Bunt9,Exp_R_Bunt10))
for inning in range(1,max_inning+1):
ave_Exp_R_Hit[inning,0] = np.average(all_Exp_R_Hit[inning,:])
ave_Exp_R_Bunt[inning,0] = np.average(all_Exp_R_Bunt[inning,:])
print "Exp_RunScore_Hitting",ave_Exp_R_Hit[max_inning,0]
print "Exp_RunScore_Bunt",ave_Exp_R_Bunt[max_inning,0]
plt.xlabel("Number of innings")
plt.ylabel("Expected Runs Score per inning")
plt.axis([0,max_inning,0.0,2])
plt.plot(Exp_R_Hit1,'r',alpha=0.2)
plt.plot(Exp_R_Hit2,'r',alpha=0.2)
plt.plot(Exp_R_Hit3,'r',alpha=0.2)
plt.plot(Exp_R_Hit4,'r',alpha=0.2)
plt.plot(Exp_R_Hit5,'r',alpha=0.2)
plt.plot(Exp_R_Hit6,'r',alpha=0.2)
plt.plot(Exp_R_Hit7,'r',alpha=0.2)
plt.plot(Exp_R_Hit8,'r',alpha=0.2)
plt.plot(Exp_R_Hit9,'r',alpha=0.2)
plt.plot(Exp_R_Hit10,'r',alpha=0.2)
plt.plot(ave_Exp_R_Hit,'r',label="Hitting")
plt.plot(Exp_R_Bunt1,'b',alpha=0.2)
plt.plot(Exp_R_Bunt2,'b',alpha=0.2)
plt.plot(Exp_R_Bunt3,'b',alpha=0.2)
plt.plot(Exp_R_Bunt4,'b',alpha=0.2)
plt.plot(Exp_R_Bunt5,'b',alpha=0.2)
plt.plot(Exp_R_Bunt6,'b',alpha=0.2)
plt.plot(Exp_R_Bunt7,'b',alpha=0.2)
plt.plot(Exp_R_Bunt8,'b',alpha=0.2)
plt.plot(Exp_R_Bunt9,'b',alpha=0.2)
plt.plot(Exp_R_Bunt10,'b',alpha=0.2)
plt.plot(ave_Exp_R_Bunt,'b',label="Bunt")
plt.legend()
plt.grid(True)
plt.savefig('ex_v2_2_Simuresult.png')
'''
plt.hist(R_array_Hit,bins=10)
plt.hist(R_array_Bunt,bins=10)
plt.show()
'''
quit()
Recommended Posts