Advertisement
Guest User

KoldunchikRatings

a guest
Nov 6th, 2013
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. from django.core.management.base import BaseCommand, CommandError
  2. from math import sqrt, fabs, pow
  3. from copy import deepcopy
  4. from collections import defaultdict
  5.  
  6. from ratings.models import Rating, Participant, ParticipantRelation
  7.  
  8. class RelationEqualizer(object):
  9.     def __init__(self, rating):
  10.         self._rating = rating
  11.         self._prel = {}
  12.         self._pmap = {}
  13.         self._antifraud = {}
  14.         self._uvn_iterations = 10 # user vector normalization iterations
  15.         self._tn_iterations = 5 # table normalization iterations
  16.  
  17.     def _print(self):
  18.         skeys = sorted(self._pmap.keys(), key=lambda x: -self._pmap[x].score)
  19.         for row_id in skeys:
  20.             vals = [ u'%20s' % self._pmap[row_id].user.username ]
  21.             total = 0.0
  22.             count = 0.0
  23.             for col_id in skeys:
  24.                 rel = self._prel[row_id][col_id]
  25.                 if rel is None:
  26.                     vals.append('U')
  27.                 elif rel > 0:
  28.                     vals.append('B')
  29.                 elif rel < 0:
  30.                     vals.append('.')
  31.                 else:
  32.                     vals.append('=')
  33.             vals.append('%5.1f' % self._user_scores(row_id))
  34.             print u' '.join(vals)
  35.  
  36.     def _user_scores(self, user):
  37.         count = len(self._pmap)
  38.         if count == 0:
  39.             return 0.0
  40.         score = 0.0
  41.  
  42.         for rel in self._prel[user].itervalues():
  43.             if rel is None:
  44.                 continue
  45.             if rel >= 0:
  46.                 score += 1
  47.             else:
  48.                 score -= 1
  49.         return pow((score / count + 1.0) * 50, 0.5) * 10
  50.  
  51.     def _load_data(self):
  52.         pmap = {}
  53.         prel = {}
  54.  
  55.         rlist = ParticipantRelation.objects.filter(subject__rating=self._rating).all()
  56.         for r in rlist:
  57.             if not r.object.active or not r.subject.active:
  58.                 continue
  59.             if not r.subject.pk in pmap:
  60.                 pmap[r.subject.pk] = r.subject
  61.             if not r.object.pk in pmap:
  62.                 pmap[r.object.pk] = r.object
  63.             if r.subject.pk not in prel:
  64.                 prel[r.subject.pk] = {}
  65.             if r.object.pk not in prel:
  66.                 prel[r.object.pk] = {}
  67.             prel[r.subject.pk][r.object.pk] = r.value
  68.  
  69.         for x in pmap.iterkeys():
  70.             for y in pmap.iterkeys():
  71.                 if y not in prel[x]:
  72.                     prel[x][y] = None
  73.                 if x == y:
  74.                     prel[x][y] = 0.0
  75.  
  76.         self._pmap = pmap
  77.         self._prel = prel
  78.  
  79.     def _load_antifraud(self):
  80.         antifraud = {}
  81.         prel = self._prel
  82.         competitors_number = len(prel)
  83.         for xid, rels in prel.iteritems():
  84.             antifraud[xid] = 1.0
  85.             count = 0.0
  86.             frauds = 0.0
  87.             for yid, rel in rels.iteritems():
  88.                 if prel[xid][yid] is None or prel[yid][xid] is None:
  89.                     continue
  90.  
  91.                 count += 1
  92.                 if prel[xid][yid] * prel[yid][xid] < 0 or prel[xid][yid] == 0 and prel[yid][xid] == 0:
  93.                     continue
  94.  
  95.                 if prel[xid][yid] * prel[yid][xid] > 0:
  96.                     frauds += 1.0
  97.                 elif prel[xid][yid] * prel[yid][xid] == 0:
  98.                     frauds += 2.0 /3.0
  99.             if count > 0:
  100.                 antifraud[xid] = pow(1.0 - frauds / count, 5)
  101.         self._antifraud = antifraud
  102.  
  103.     def _stronger_weaker_equals(self, id, weight, s, e, w):
  104.  
  105.         for yidx in self._prel.iterkeys():
  106.             rel = self._prel[id][yidx]
  107.             if rel is not None:
  108.                 if rel > 0:
  109.                     w[yidx] += weight * self._antifraud[id]
  110.                 elif rel < 0:
  111.                     s[yidx] += weight * self._antifraud[id]
  112.                 elif rel == 0:
  113.                     e[yidx] += weight * self._antifraud[id]
  114.  
  115.             rel = self._prel[yidx][id]
  116.             if rel is not None:
  117.                 if rel < 0:
  118.                     w[yidx] += weight * self._antifraud[yidx]
  119.                 elif rel > 0:
  120.                     s[yidx] += weight * self._antifraud[yidx]
  121.                 elif rel == 0:
  122.                     e[yidx] += weight * self._antifraud[yidx]
  123.  
  124.     def _update_user_vector(self, user):
  125.  
  126.         stronger = defaultdict(lambda: 0.0) # players that stronger than user
  127.         equals = defaultdict(lambda: 0.0)
  128.         weaker = defaultdict(lambda: 0.0)
  129.         equals[user] = 1
  130.  
  131.         for i in xrange(0, self._uvn_iterations):
  132.             dummy = defaultdict(lambda: 0.0)
  133.             s = defaultdict(lambda: 0.0)
  134.             w = defaultdict(lambda: 0.0)
  135.             e = defaultdict(lambda: 0.0)
  136.  
  137.             for yidx, yval in stronger.iteritems():
  138.                 self._stronger_weaker_equals(yidx, yval, s, s, dummy)
  139.  
  140.             for yidx, yval in equals.iteritems():
  141.                 self._stronger_weaker_equals(yidx, yval, s, e, w)
  142.  
  143.             for yidx, yval in weaker.iteritems():
  144.                 self._stronger_weaker_equals(yidx, yval, dummy, w, w)
  145.  
  146.             for k in set(s.keys()) | set(e.keys()) | set(w.keys()):
  147.                 sum = s[k] + w[k] + e[k]
  148.                 if sum > 0:
  149.                     s[k] /= sum
  150.                     e[k] /= sum
  151.                     w[k] /= sum
  152.  
  153.             stronger = s
  154.             equals = e
  155.             weaker = w
  156.  
  157.         result = {}
  158.         for idx in self._prel.iterkeys():
  159.             result[idx] = w[idx] - s[idx]
  160.             if fabs(result[idx]) <= 1.0 / 3:
  161.                 result[idx] = 0.0
  162.         return result
  163.  
  164.     def relations(self):
  165.         self._load_data()
  166.         for i in xrange(0, self._tn_iterations):
  167.             new_prel = {}
  168.             self._load_antifraud()
  169.             for user in self._prel.iterkeys():
  170.                 new_prel[user] = self._update_user_vector(user)
  171.             self._prel = new_prel
  172.         return self._prel
  173.  
  174.     def update_rates(self):
  175.         self._load_data()
  176.         self._print()
  177.         prel = self.relations()
  178.         print ""
  179.         self._print()
  180.         for user in prel.iterkeys():
  181.             uname = self._pmap[user].user.username.encode('utf8', 'ignore')
  182.             self._pmap[user].score = self._user_scores(user)
  183.             self._pmap[user].save()
  184.             print "User %s scores %f" % (uname, self._pmap[user].score)
  185.  
  186. class Command(BaseCommand):
  187.     help = 'ratings normalization'
  188.  
  189.     def handle(self, *args, **kwargs):
  190.         for r in Rating.objects.all():
  191.             self.stdout.write("Processing rating %s" % r.title)
  192.             req = RelationEqualizer(r)
  193.             req.update_rates()
  194.             self.stdout.write("")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement