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 = {} |