Mixin enabling a weighted majority voting system for any model with qualitative decisions/categories. As measure of consensus/inter-rater agreement, you can choose between a weighted variant of the Fleiss’s Kappa (by default) or the entropy of the distribution of votes. The consensus score is in the interval [0,1]. very high consensus=1 , very low consensus=0
NOTE: this voting system has been developed to take (collective) a decision about items, not rank items (e.g. by popularity). i.e. generally once a certain level of consensus is reached on a given item, a decision is taken and the vote is close.
You have a set of items and would like to classify them according to n predefined categories. For that you ask the opinion of the public. Since some people are better/more reliable than others, their votes can be weighted so they have more power in the collective decision.
To use it, add it to your Gemfile:
gem 'acts_as_meritocracy'
class Item < ActiveRecord::Base act_as_meritocracy end item = Item.create() #user1 votes for the decision 4, by default the vote_weight=1 item.submit_vote(user1, 4) # user2 votes for the decision 1 with a vote_weight=2. A vote_weight=2 means that # the voter has a vote equal to 2 normal voters (vote_weight=1) item.submit_vote(user2, 1, 2) # user1 can change/update her vote item.submit_vote(user1, 1) # user3 votes for decision 2 item.submit_vote(user3, 2) # user4 votes for decision 2 item.submit_vote(user4, 3,5) # getting the most (weighted) voted decision # tie management: you can manage tie with 2 methods # - best_decision("random") (by default) returns randomly one of the categories having the same highest frequency # - best_desion("nodecision") returns nil if a tie is detected item.best_decision =>3 # getting the number of votes - with the weight item.nb_votes(true) => 1 + 2 + 1 + 5 = 9 # getting the number of votes - without taking into account the weight item.nb_votes(false) => 1 + 1 + 1 + 1 = 4 # getting the frequency distribution of the decisions [{:decision1=>freq1},{:decision1=>freq2}, ..,]. # the frequency takes into account the vote weight. item.vote_distribution => [ {vote => 1, freq => 3},{vote => 2, freq => 1},{vote => 3,freq => 5} ] # computing the consensus score based on the vote distribution # by default I used a variante of the Fleiss Kappa metrics item.consensus => 0.361 # Alternative: computing an entropy-based measure of the consensus # (A perfect disagreement between 2 categories gives a higher score # than for 10 categories, less predictable) item.consensus("entropy") =>0.063 # retrieving the list of votes {decision, vote_weight). # so item.votes.where(:vote=>1) retrieves the list of votes having decision=1 item.votes => [Vote1<>.,Vote2<>., .., Voten<>. ] # getting all the items voted by user1 item.voted_by?(user1) => yes # getting all the items voted by user1 Item.voted_by(user1) =>[item]