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 87 sum += item_and_weight[1]
88 88 end
89 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 94 elsif weighted.instance_of?(Array)
92 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 101 end
95 102 end
96 103  
... ... @@ -98,6 +105,8 @@ class Question < ActiveRecord::Base
98 105 probs = []
99 106 prev_probs = []
100 107  
  108 + fuzz = 0.001
  109 +
101 110 # What ordering key we use is unimportant, just need a consistent way to link index of prob to id
102 111 the_choices = self.choices.sort{|x,y| x.id<=>y.id}
103 112  
... ... @@ -112,15 +121,19 @@ class Question &lt; ActiveRecord::Base
112 121  
113 122 t=0
114 123 probs_size = probs.size
  124 +
  125 + difference = 1
115 126  
116 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 129 s = t % probs_size
119 130 prev_probs = probs.dup
120 131 choice = the_choices[s]
121 132  
122 133 numerator = choice.wins.to_f
123 134  
  135 +
  136 +
124 137 denominator = 0.0
125 138 the_choices.each_with_index do |c, index|
126 139 if(index == s)
... ... @@ -128,11 +141,20 @@ class Question &lt; ActiveRecord::Base
128 141 end
129 142  
130 143 wins_and_losses = the_prompts["#{choice.id}, #{c.id}"].votes.size + the_prompts["#{c.id}, #{choice.id}"].votes.size
  144 +
131 145 denominator+= (wins_and_losses).to_f / (prev_probs[s] + prev_probs[index])
132 146 end
133 147 probs[s] = numerator / denominator
  148 + # avoid divide by zero NaN
  149 + probs[s] = 0.0 unless probs[s].finite?
134 150 normalize!(probs)
135 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 158 end
137 159  
138 160 probs_hash = {}
... ...