Created
May 22, 2012 23:50
-
-
Save hiro88hyo/2772407 to your computer and use it in GitHub Desktop.
Betting simulation with GA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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