Commit 780cec070170e12adfd6d2ee78b1c1b6fde1498f

Authored by Dhruv Kapadia
1 parent 9a5a6e19

Improvements to bradley terry calculations

Showing 1 changed file with 25 additions and 3 deletions   Show diff stats
app/models/question.rb
@@ -87,10 +87,17 @@ class Question < ActiveRecord::Base @@ -87,10 +87,17 @@ class Question < ActiveRecord::Base
87 sum += item_and_weight[1] 87 sum += item_and_weight[1]
88 end 88 end
89 sum = sum.to_f 89 sum = sum.to_f
90 - weighted.each { |item, weight| weighted[item] = weight/sum } 90 + weighted.each do |item, weight|
  91 + weighted[item] = weight/sum
  92 + weighted[item] = 0.0 unless weighted[item].finite?
  93 + end
91 elsif weighted.instance_of?(Array) 94 elsif weighted.instance_of?(Array)
92 sum = weighted.inject(0) {|sum, item| sum += item} 95 sum = weighted.inject(0) {|sum, item| sum += item}
93 - weighted.each_with_index {|item, i| weighted[i] = item/sum} 96 + weighted.each_with_index do |item, i|
  97 + weighted[i] = item/sum
  98 + weighted[i] = 0.0 unless weighted[i].finite?
  99 + end
  100 +
94 end 101 end
95 end 102 end
96 103
@@ -98,6 +105,8 @@ class Question < ActiveRecord::Base @@ -98,6 +105,8 @@ class Question < ActiveRecord::Base
98 probs = [] 105 probs = []
99 prev_probs = [] 106 prev_probs = []
100 107
  108 + fuzz = 0.001
  109 +
101 # What ordering key we use is unimportant, just need a consistent way to link index of prob to id 110 # What ordering key we use is unimportant, just need a consistent way to link index of prob to id
102 the_choices = self.choices.sort{|x,y| x.id<=>y.id} 111 the_choices = self.choices.sort{|x,y| x.id<=>y.id}
103 112
@@ -112,15 +121,19 @@ class Question &lt; ActiveRecord::Base @@ -112,15 +121,19 @@ class Question &lt; ActiveRecord::Base
112 121
113 t=0 122 t=0
114 probs_size = probs.size 123 probs_size = probs.size
  124 +
  125 + difference = 1
115 126
116 # probably want to add a fuzz here to account for floating rounding 127 # probably want to add a fuzz here to account for floating rounding
117 - until probs == prev_probs do 128 + while difference > fuzz do
118 s = t % probs_size 129 s = t % probs_size
119 prev_probs = probs.dup 130 prev_probs = probs.dup
120 choice = the_choices[s] 131 choice = the_choices[s]
121 132
122 numerator = choice.wins.to_f 133 numerator = choice.wins.to_f
123 134
  135 +
  136 +
124 denominator = 0.0 137 denominator = 0.0
125 the_choices.each_with_index do |c, index| 138 the_choices.each_with_index do |c, index|
126 if(index == s) 139 if(index == s)
@@ -128,11 +141,20 @@ class Question &lt; ActiveRecord::Base @@ -128,11 +141,20 @@ class Question &lt; ActiveRecord::Base
128 end 141 end
129 142
130 wins_and_losses = the_prompts["#{choice.id}, #{c.id}"].votes.size + the_prompts["#{c.id}, #{choice.id}"].votes.size 143 wins_and_losses = the_prompts["#{choice.id}, #{c.id}"].votes.size + the_prompts["#{c.id}, #{choice.id}"].votes.size
  144 +
131 denominator+= (wins_and_losses).to_f / (prev_probs[s] + prev_probs[index]) 145 denominator+= (wins_and_losses).to_f / (prev_probs[s] + prev_probs[index])
132 end 146 end
133 probs[s] = numerator / denominator 147 probs[s] = numerator / denominator
  148 + # avoid divide by zero NaN
  149 + probs[s] = 0.0 unless probs[s].finite?
134 normalize!(probs) 150 normalize!(probs)
135 t+=1 151 t+=1
  152 +
  153 + difference = 0
  154 + probs.each_with_index do |curr, index|
  155 + difference += (curr - prev_probs[index]).abs
  156 + end
  157 + puts difference
136 end 158 end
137 159
138 probs_hash = {} 160 probs_hash = {}