Commit 780cec070170e12adfd6d2ee78b1c1b6fde1498f
1 parent
9a5a6e19
Exists in
master
and in
1 other branch
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 < ActiveRecord::Base | @@ -112,15 +121,19 @@ class Question < 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 < ActiveRecord::Base | @@ -128,11 +141,20 @@ class Question < 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 = {} |