Skip to content

Instantly share code, notes, and snippets.

@hiro88hyo
Created May 22, 2012 23:50
Show Gist options
  • Save hiro88hyo/2772407 to your computer and use it in GitHub Desktop.
Save hiro88hyo/2772407 to your computer and use it in GitHub Desktop.
Betting simulation with GA
require 'enumerator'
class BetGA
attr_accessor :amount
def initialize(o) # 初期化 入力:オッズ
@odds = o
@prob = Array.new() # 確率
@bets = Array.new() # 投票
@amounts = 50 # 購入数
@populations = 50 # 生き残り
@num_children = 500 # 子の数
@mutation_p = 5.0 # 突然変異の確率(%)
@adjust_p = 0.5
calc_prob()
first_generation()
end
def calc_sum(b) # 総投票数
sum = 0.0
b.each{|i|
sum += i
}
sum
end
def calc_prob # 確率計算
sum = 0.0
@odds.each{|o|
sum += 1/o.to_f
}
@odds.each_index{|i|
@prob[i] = (1/@odds[i])/sum
}
end
def first_generation # 初期シード
@populations.times{|c|
b = Array.new(@odds.length, 1)
count = @amounts
while count>0
i = rand(@odds.length)
a = (rand(10)-4).to_i
b[i] += a
if b[i]<1
b[i] = 1
count += a
else
count -= a
end
end
@bets.push(b)
}
end
def next_generation # 世代交代
crossover()
selection()
end
def crossover # 交叉
@num_children.times{|i|
p1 = @bets[rand(@bets.length)]
p2 = @bets[rand(@bets.length)]
child = co_two_point(p1,p2)
@bets.push child
}
end
def co_two_point(p1, p2) # 2点交叉
c = Array.new
cp1 = rand(p1.length)
cp2 = rand(p1.length-cp1)
c += p1.slice(0,cp1)
c += p2.slice(cp1,cp2) if cp2>0
c += p1.slice(cp1+cp2..p1.length)
c = mutation(c)
c = adapt(c)
return c
end
def adapt(c)
if rand(100)<@adjust_p
c = adjust(c)
end
return c
end
def mutation(c) # 突然変異
if rand(100)<@mutation_p
p1 = rand(c.length)
p2 = rand(c.length)
t = c[p1]
c[p1]=c[p2]
c[p2]=t
end
return c
end
def selection # 選択
result = sel_tournament(@bets, @populations, 1)
@bets = result
end
def sel_tournament(children, div, limit) # div:分割数, limit:上位何位までか
alived = Array.new
children.each_slice(children.length/div){|s|
alived.push(get_top_n(s, limit))
}
return alived
end
def get_top_n(c, n) # 上位n位まで抽出
rank = Array.new
result = Array.new
c.each_index{|i|
rank.push([i, evaluate(c[i])])
}
rank.sort!{|a,b|b[1]<=>a[1]}
n.times{|i|
result.push(c[rank[i][0]])
}
return result.flatten
end
def evaluate(bet) # 評価関数
# return ev_v1(bet)
return ev_v2(bet)
end
def average(a)
s = 0.0
a.each{|b| s += b}
return s/a.length
end
def variance(a)
s = 0.0
av = average(a)
a.each{|b|
s += (b-av)*(b-av)
}
return s/(a.length-1)
end
def ev_v1(bet) # 評価関数
sum = calc_sum(bet)
e = 0.0
rate=Array.new
bet.each_index{|i|
r = bet[i] * @odds[i]/sum
if r>1.0 # 回収率100%以上のものについて加算
if r<10 # 回収率1000%以上は無視
e += bet[i] * @odds[i] * @prob[i]
end
else # 回収率100%未満は減点
e -= (bet[i] * @odds[i] * @prob[i])
end
}
return e
end
def ev_v2(bet)
# rev1 分散が小さいほど高評価→回収率100%以下に収束しがち
# rev2 回収率100%からの乖離率を加味する
# rev3 期待値を加味する
sum = calc_sum(bet)
exp = 0.0
rate=Array.new
bet.each_index{|i|
r = bet[i] * @odds[i]/sum
rate.push(r)
exp = @prob[i] * r
}
return exp * (120.0/(120.0-average(rate)).abs/100.0) * 1/(variance(rate))
end
def best
get_top_n(@bets, 1)
end
def print_result(b) # 結果出力
sum = calc_sum(b)
puts "---------"
@odds.length.times{|o|
printf("%2d : %3d * %5.1f => %6d %6.5f %6.1f\n", o+1, b[o], @odds[o], b[o]*@odds[o], @prob[o], 100*b[o]*@odds[o]/sum)
}
puts "sum=#{sum}, E=#{evaluate(b)}"
end
def adjust(b) # 回収率100%以下に対して補正
sum = calc_sum(b)
b.each_index{|i|
while (100*b[i]*@odds[i]/sum<100.0) and (calc_sum(b)<@amounts)
b[i] += 1
end
}
return b
end
end
odds = Array.new()
#odds = [1.6, 2.6, 8.0, 13.3, 20.0]
# 20120520 tko 01R -> 15
odds[0] = [4.9,58.0,4.5,190.1,18.3,105.7,184.3,109.6,6.6,5.1,5.3,15.4,245.7,84.5,21.7,15.7]
# 20120520 tko 02R -> 16
odds[1] = [106.4,42.7,13.0,110.7,186.5,542.1,240.2,29.1,44.1,79.8,170.9,1.8,6.6,5.5,90.8,7.2]
# 20120520 tko 03R -> 14
odds[2] = [19.2,446.6,47.6,16.5,291.5,285.5,52.3,165.2,26.3,188.4,2.9,44.7,304.3,1.6,261.5,51.0]
# 20120520 tko 04R -> 05
odds[3] = [19.7,15.3,29.5,61.7,3.0,149.0,13.1,10.4,34.2,8.9,353.8,145.9,3.4,361.5,141.9,52.0,9.4]
# 20120520 tko 05R -> 07
odds[4] = [24.8,67.6,212.4,45.2,241.4,7.5,1.7,5.6,74.7,10.9,6.2]
# 20120520 tko 06R -> 11
odds[5] = [57.6,8.0,254.5,156.1,159.5,80.7,2.4,17.5,80.6,4.2,8.9,13.7,37.7,68.9,21.6,11.2]
# 20120520 tko 07R -> 02
odds[6] = [23.2,1.9,81.8,5.2,8.6,83.3,10.1,15.5,89.2,159.8,63.9,64.2,43.6,286.8,11.4,51.6]
# 20120520 tko 08R -> 07
odds[7] = [3.0,158.2,3.3,25.0,18.0,179.4,6.4,109.3,19.2,219.6,6.7,17.6,202.5,43.5,35.9,45.6]
# 20120520 tko 09R -> 16
odds[8] = [217.5,16.8,13.3,8.7,247.8,5.5,9.9,8.9,45.6,157.5,25.0,30.9,168.8,28.9,4.0,4.6]
# 20120520 tko 10R -> 11
odds[9] = [122.2,46.3,15.7,109.0,9.7,123.4,56.0,32.2,6.8,5.2,33.4,153.1,8.1,148.2,2.4,258.3,16.5]
# 20120520 tko 11R -> 14
odds[10] = [7.7, 78.6, 27.2, 39.0, 19.0, 79.4, 25.3, 3.3, 3.6, 15.5, 151.7, 58.5, 74.4, 5.6, 143.4, 23.0, 39.4, 83.3]
# 20120520 tko 12R -> 12
odds[11] = [4.4,68.1,25.3,6.0,144.4,31.8,135.9,5.1,5.6,3.6,47.0,11.0]
r=5
res=Array.new
b = BetGA.new(odds[r])
300.times{|i|
puts "Generation: #{(i+1)}, E=#{b.evaluate(b.best)}"
b.next_generation()
}
b.print_result(b.best)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment